1e4b17023SJohn Marino /* String length optimization
2e4b17023SJohn Marino Copyright (C) 2011 Free Software Foundation, Inc.
3e4b17023SJohn Marino Contributed by Jakub Jelinek <jakub@redhat.com>
4e4b17023SJohn Marino
5e4b17023SJohn Marino This file is part of GCC.
6e4b17023SJohn Marino
7e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify
8e4b17023SJohn Marino it under the terms of the GNU General Public License as published by
9e4b17023SJohn Marino the Free Software Foundation; either version 3, or (at your option)
10e4b17023SJohn Marino any later version.
11e4b17023SJohn Marino
12e4b17023SJohn Marino GCC is distributed in the hope that it will be useful,
13e4b17023SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
14e4b17023SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15e4b17023SJohn Marino GNU General Public License for more details.
16e4b17023SJohn Marino
17e4b17023SJohn Marino You should have received a copy of the GNU General Public License
18e4b17023SJohn Marino along with GCC; see the file COPYING3. If not see
19e4b17023SJohn Marino <http://www.gnu.org/licenses/>. */
20e4b17023SJohn Marino
21e4b17023SJohn Marino #include "config.h"
22e4b17023SJohn Marino #include "system.h"
23e4b17023SJohn Marino #include "coretypes.h"
24e4b17023SJohn Marino #include "tree-flow.h"
25e4b17023SJohn Marino #include "tree-pass.h"
26e4b17023SJohn Marino #include "domwalk.h"
27e4b17023SJohn Marino #include "alloc-pool.h"
28e4b17023SJohn Marino #include "tree-ssa-propagate.h"
29e4b17023SJohn Marino #include "gimple-pretty-print.h"
30e4b17023SJohn Marino #include "params.h"
31e4b17023SJohn Marino #include "expr.h"
32e4b17023SJohn Marino
33e4b17023SJohn Marino /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
34e4b17023SJohn Marino is an index into strinfo vector, negative value stands for
35e4b17023SJohn Marino string length of a string literal (~strlen). */
36e4b17023SJohn Marino static VEC (int, heap) *ssa_ver_to_stridx;
37e4b17023SJohn Marino
38e4b17023SJohn Marino /* Number of currently active string indexes plus one. */
39e4b17023SJohn Marino static int max_stridx;
40e4b17023SJohn Marino
41e4b17023SJohn Marino /* String information record. */
42e4b17023SJohn Marino typedef struct strinfo_struct
43e4b17023SJohn Marino {
44e4b17023SJohn Marino /* String length of this string. */
45e4b17023SJohn Marino tree length;
46e4b17023SJohn Marino /* Any of the corresponding pointers for querying alias oracle. */
47e4b17023SJohn Marino tree ptr;
48e4b17023SJohn Marino /* Statement for delayed length computation. */
49e4b17023SJohn Marino gimple stmt;
50e4b17023SJohn Marino /* Pointer to '\0' if known, if NULL, it can be computed as
51e4b17023SJohn Marino ptr + length. */
52e4b17023SJohn Marino tree endptr;
53e4b17023SJohn Marino /* Reference count. Any changes to strinfo entry possibly shared
54e4b17023SJohn Marino with dominating basic blocks need unshare_strinfo first, except
55e4b17023SJohn Marino for dont_invalidate which affects only the immediately next
56e4b17023SJohn Marino maybe_invalidate. */
57e4b17023SJohn Marino int refcount;
58e4b17023SJohn Marino /* Copy of index. get_strinfo (si->idx) should return si; */
59e4b17023SJohn Marino int idx;
60e4b17023SJohn Marino /* These 3 fields are for chaining related string pointers together.
61e4b17023SJohn Marino E.g. for
62e4b17023SJohn Marino bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
63e4b17023SJohn Marino strcpy (c, d); e = c + dl;
64e4b17023SJohn Marino strinfo(a) -> strinfo(c) -> strinfo(e)
65e4b17023SJohn Marino All have ->first field equal to strinfo(a)->idx and are doubly
66e4b17023SJohn Marino chained through prev/next fields. The later strinfos are required
67e4b17023SJohn Marino to point into the same string with zero or more bytes after
68e4b17023SJohn Marino the previous pointer and all bytes in between the two pointers
69e4b17023SJohn Marino must be non-zero. Functions like strcpy or memcpy are supposed
70e4b17023SJohn Marino to adjust all previous strinfo lengths, but not following strinfo
71e4b17023SJohn Marino lengths (those are uncertain, usually invalidated during
72e4b17023SJohn Marino maybe_invalidate, except when the alias oracle knows better).
73e4b17023SJohn Marino Functions like strcat on the other side adjust the whole
74e4b17023SJohn Marino related strinfo chain.
75e4b17023SJohn Marino They are updated lazily, so to use the chain the same first fields
76e4b17023SJohn Marino and si->prev->next == si->idx needs to be verified. */
77e4b17023SJohn Marino int first;
78e4b17023SJohn Marino int next;
79e4b17023SJohn Marino int prev;
80e4b17023SJohn Marino /* A flag whether the string is known to be written in the current
81e4b17023SJohn Marino function. */
82e4b17023SJohn Marino bool writable;
83e4b17023SJohn Marino /* A flag for the next maybe_invalidate that this strinfo shouldn't
84e4b17023SJohn Marino be invalidated. Always cleared by maybe_invalidate. */
85e4b17023SJohn Marino bool dont_invalidate;
86e4b17023SJohn Marino } *strinfo;
87e4b17023SJohn Marino DEF_VEC_P(strinfo);
88e4b17023SJohn Marino DEF_VEC_ALLOC_P(strinfo,heap);
89e4b17023SJohn Marino
90e4b17023SJohn Marino /* Pool for allocating strinfo_struct entries. */
91e4b17023SJohn Marino static alloc_pool strinfo_pool;
92e4b17023SJohn Marino
93e4b17023SJohn Marino /* Vector mapping positive string indexes to strinfo, for the
94e4b17023SJohn Marino current basic block. The first pointer in the vector is special,
95e4b17023SJohn Marino it is either NULL, meaning the vector isn't shared, or it is
96e4b17023SJohn Marino a basic block pointer to the owner basic_block if shared.
97e4b17023SJohn Marino If some other bb wants to modify the vector, the vector needs
98e4b17023SJohn Marino to be unshared first, and only the owner bb is supposed to free it. */
VEC(strinfo,heap)99e4b17023SJohn Marino static VEC(strinfo, heap) *stridx_to_strinfo;
100e4b17023SJohn Marino
101e4b17023SJohn Marino /* One OFFSET->IDX mapping. */
102e4b17023SJohn Marino struct stridxlist
103e4b17023SJohn Marino {
104e4b17023SJohn Marino struct stridxlist *next;
105e4b17023SJohn Marino HOST_WIDE_INT offset;
106e4b17023SJohn Marino int idx;
107e4b17023SJohn Marino };
108e4b17023SJohn Marino
109e4b17023SJohn Marino /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
110e4b17023SJohn Marino struct decl_stridxlist_map
111e4b17023SJohn Marino {
112e4b17023SJohn Marino struct tree_map_base base;
113e4b17023SJohn Marino struct stridxlist list;
114e4b17023SJohn Marino };
115e4b17023SJohn Marino
116e4b17023SJohn Marino /* Hash table for mapping decls to a chained list of offset -> idx
117e4b17023SJohn Marino mappings. */
118e4b17023SJohn Marino static htab_t decl_to_stridxlist_htab;
119e4b17023SJohn Marino
120e4b17023SJohn Marino /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
121e4b17023SJohn Marino static struct obstack stridx_obstack;
122e4b17023SJohn Marino
123e4b17023SJohn Marino /* Last memcpy statement if it could be adjusted if the trailing
124e4b17023SJohn Marino '\0' written is immediately overwritten, or
125e4b17023SJohn Marino *x = '\0' store that could be removed if it is immediately overwritten. */
126e4b17023SJohn Marino struct laststmt_struct
127e4b17023SJohn Marino {
128e4b17023SJohn Marino gimple stmt;
129e4b17023SJohn Marino tree len;
130e4b17023SJohn Marino int stridx;
131e4b17023SJohn Marino } laststmt;
132e4b17023SJohn Marino
133e4b17023SJohn Marino /* Hash a from tree in a decl_stridxlist_map. */
134e4b17023SJohn Marino
135e4b17023SJohn Marino static unsigned int
decl_to_stridxlist_hash(const void * item)136e4b17023SJohn Marino decl_to_stridxlist_hash (const void *item)
137e4b17023SJohn Marino {
138e4b17023SJohn Marino return DECL_UID (((const struct decl_stridxlist_map *) item)->base.from);
139e4b17023SJohn Marino }
140e4b17023SJohn Marino
141e4b17023SJohn Marino /* Helper function for get_stridx. */
142e4b17023SJohn Marino
143e4b17023SJohn Marino static int
get_addr_stridx(tree exp)144e4b17023SJohn Marino get_addr_stridx (tree exp)
145e4b17023SJohn Marino {
146e4b17023SJohn Marino HOST_WIDE_INT off;
147e4b17023SJohn Marino struct decl_stridxlist_map ent, *e;
148e4b17023SJohn Marino struct stridxlist *list;
149e4b17023SJohn Marino tree base;
150e4b17023SJohn Marino
151e4b17023SJohn Marino if (decl_to_stridxlist_htab == NULL)
152e4b17023SJohn Marino return 0;
153e4b17023SJohn Marino
154e4b17023SJohn Marino base = get_addr_base_and_unit_offset (exp, &off);
155e4b17023SJohn Marino if (base == NULL || !DECL_P (base))
156e4b17023SJohn Marino return 0;
157e4b17023SJohn Marino
158e4b17023SJohn Marino ent.base.from = base;
159e4b17023SJohn Marino e = (struct decl_stridxlist_map *)
160e4b17023SJohn Marino htab_find_with_hash (decl_to_stridxlist_htab, &ent, DECL_UID (base));
161e4b17023SJohn Marino if (e == NULL)
162e4b17023SJohn Marino return 0;
163e4b17023SJohn Marino
164e4b17023SJohn Marino list = &e->list;
165e4b17023SJohn Marino do
166e4b17023SJohn Marino {
167e4b17023SJohn Marino if (list->offset == off)
168e4b17023SJohn Marino return list->idx;
169e4b17023SJohn Marino list = list->next;
170e4b17023SJohn Marino }
171e4b17023SJohn Marino while (list);
172e4b17023SJohn Marino return 0;
173e4b17023SJohn Marino }
174e4b17023SJohn Marino
175e4b17023SJohn Marino /* Return string index for EXP. */
176e4b17023SJohn Marino
177e4b17023SJohn Marino static int
get_stridx(tree exp)178e4b17023SJohn Marino get_stridx (tree exp)
179e4b17023SJohn Marino {
180e4b17023SJohn Marino tree s, o;
181e4b17023SJohn Marino
182e4b17023SJohn Marino if (TREE_CODE (exp) == SSA_NAME)
183e4b17023SJohn Marino return VEC_index (int, ssa_ver_to_stridx, SSA_NAME_VERSION (exp));
184e4b17023SJohn Marino
185e4b17023SJohn Marino if (TREE_CODE (exp) == ADDR_EXPR)
186e4b17023SJohn Marino {
187e4b17023SJohn Marino int idx = get_addr_stridx (TREE_OPERAND (exp, 0));
188e4b17023SJohn Marino if (idx != 0)
189e4b17023SJohn Marino return idx;
190e4b17023SJohn Marino }
191e4b17023SJohn Marino
192e4b17023SJohn Marino s = string_constant (exp, &o);
193e4b17023SJohn Marino if (s != NULL_TREE
194e4b17023SJohn Marino && (o == NULL_TREE || host_integerp (o, 0))
195e4b17023SJohn Marino && TREE_STRING_LENGTH (s) > 0)
196e4b17023SJohn Marino {
197e4b17023SJohn Marino HOST_WIDE_INT offset = o ? tree_low_cst (o, 0) : 0;
198e4b17023SJohn Marino const char *p = TREE_STRING_POINTER (s);
199e4b17023SJohn Marino int max = TREE_STRING_LENGTH (s) - 1;
200e4b17023SJohn Marino
201e4b17023SJohn Marino if (p[max] == '\0' && offset >= 0 && offset <= max)
202e4b17023SJohn Marino return ~(int) strlen (p + offset);
203e4b17023SJohn Marino }
204e4b17023SJohn Marino return 0;
205e4b17023SJohn Marino }
206e4b17023SJohn Marino
207e4b17023SJohn Marino /* Return true if strinfo vector is shared with the immediate dominator. */
208e4b17023SJohn Marino
209e4b17023SJohn Marino static inline bool
strinfo_shared(void)210e4b17023SJohn Marino strinfo_shared (void)
211e4b17023SJohn Marino {
212e4b17023SJohn Marino return VEC_length (strinfo, stridx_to_strinfo)
213e4b17023SJohn Marino && VEC_index (strinfo, stridx_to_strinfo, 0) != NULL;
214e4b17023SJohn Marino }
215e4b17023SJohn Marino
216e4b17023SJohn Marino /* Unshare strinfo vector that is shared with the immediate dominator. */
217e4b17023SJohn Marino
218e4b17023SJohn Marino static void
unshare_strinfo_vec(void)219e4b17023SJohn Marino unshare_strinfo_vec (void)
220e4b17023SJohn Marino {
221e4b17023SJohn Marino strinfo si;
222e4b17023SJohn Marino unsigned int i = 0;
223e4b17023SJohn Marino
224e4b17023SJohn Marino gcc_assert (strinfo_shared ());
225e4b17023SJohn Marino stridx_to_strinfo = VEC_copy (strinfo, heap, stridx_to_strinfo);
226e4b17023SJohn Marino for (i = 1; VEC_iterate (strinfo, stridx_to_strinfo, i, si); ++i)
227e4b17023SJohn Marino if (si != NULL)
228e4b17023SJohn Marino si->refcount++;
229e4b17023SJohn Marino VEC_replace (strinfo, stridx_to_strinfo, 0, NULL);
230e4b17023SJohn Marino }
231e4b17023SJohn Marino
232e4b17023SJohn Marino /* Attempt to create a string index for exp, ADDR_EXPR's operand.
233e4b17023SJohn Marino Return a pointer to the location where the string index can
234e4b17023SJohn Marino be stored (if 0) or is stored, or NULL if this can't be tracked. */
235e4b17023SJohn Marino
236e4b17023SJohn Marino static int *
addr_stridxptr(tree exp)237e4b17023SJohn Marino addr_stridxptr (tree exp)
238e4b17023SJohn Marino {
239e4b17023SJohn Marino void **slot;
240e4b17023SJohn Marino struct decl_stridxlist_map ent;
241e4b17023SJohn Marino struct stridxlist *list;
242e4b17023SJohn Marino HOST_WIDE_INT off;
243e4b17023SJohn Marino
244e4b17023SJohn Marino tree base = get_addr_base_and_unit_offset (exp, &off);
245e4b17023SJohn Marino if (base == NULL_TREE || !DECL_P (base))
246e4b17023SJohn Marino return NULL;
247e4b17023SJohn Marino
248e4b17023SJohn Marino if (decl_to_stridxlist_htab == NULL)
249e4b17023SJohn Marino {
250e4b17023SJohn Marino decl_to_stridxlist_htab
251e4b17023SJohn Marino = htab_create (64, decl_to_stridxlist_hash, tree_map_base_eq, NULL);
252e4b17023SJohn Marino gcc_obstack_init (&stridx_obstack);
253e4b17023SJohn Marino }
254e4b17023SJohn Marino ent.base.from = base;
255e4b17023SJohn Marino slot = htab_find_slot_with_hash (decl_to_stridxlist_htab, &ent,
256e4b17023SJohn Marino DECL_UID (base), INSERT);
257e4b17023SJohn Marino if (*slot)
258e4b17023SJohn Marino {
259e4b17023SJohn Marino int i;
260e4b17023SJohn Marino list = &((struct decl_stridxlist_map *)*slot)->list;
261e4b17023SJohn Marino for (i = 0; i < 16; i++)
262e4b17023SJohn Marino {
263e4b17023SJohn Marino if (list->offset == off)
264e4b17023SJohn Marino return &list->idx;
265e4b17023SJohn Marino if (list->next == NULL)
266e4b17023SJohn Marino break;
267e4b17023SJohn Marino }
268e4b17023SJohn Marino if (i == 16)
269e4b17023SJohn Marino return NULL;
270e4b17023SJohn Marino list->next = XOBNEW (&stridx_obstack, struct stridxlist);
271e4b17023SJohn Marino list = list->next;
272e4b17023SJohn Marino }
273e4b17023SJohn Marino else
274e4b17023SJohn Marino {
275e4b17023SJohn Marino struct decl_stridxlist_map *e
276e4b17023SJohn Marino = XOBNEW (&stridx_obstack, struct decl_stridxlist_map);
277e4b17023SJohn Marino e->base.from = base;
278e4b17023SJohn Marino *slot = (void *) e;
279e4b17023SJohn Marino list = &e->list;
280e4b17023SJohn Marino }
281e4b17023SJohn Marino list->next = NULL;
282e4b17023SJohn Marino list->offset = off;
283e4b17023SJohn Marino list->idx = 0;
284e4b17023SJohn Marino return &list->idx;
285e4b17023SJohn Marino }
286e4b17023SJohn Marino
287e4b17023SJohn Marino /* Create a new string index, or return 0 if reached limit. */
288e4b17023SJohn Marino
289e4b17023SJohn Marino static int
new_stridx(tree exp)290e4b17023SJohn Marino new_stridx (tree exp)
291e4b17023SJohn Marino {
292e4b17023SJohn Marino int idx;
293e4b17023SJohn Marino if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
294e4b17023SJohn Marino return 0;
295e4b17023SJohn Marino if (TREE_CODE (exp) == SSA_NAME)
296e4b17023SJohn Marino {
297e4b17023SJohn Marino if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
298e4b17023SJohn Marino return 0;
299e4b17023SJohn Marino idx = max_stridx++;
300e4b17023SJohn Marino VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (exp), idx);
301e4b17023SJohn Marino return idx;
302e4b17023SJohn Marino }
303e4b17023SJohn Marino if (TREE_CODE (exp) == ADDR_EXPR)
304e4b17023SJohn Marino {
305e4b17023SJohn Marino int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
306e4b17023SJohn Marino if (pidx != NULL)
307e4b17023SJohn Marino {
308e4b17023SJohn Marino gcc_assert (*pidx == 0);
309e4b17023SJohn Marino *pidx = max_stridx++;
310e4b17023SJohn Marino return *pidx;
311e4b17023SJohn Marino }
312e4b17023SJohn Marino }
313e4b17023SJohn Marino return 0;
314e4b17023SJohn Marino }
315e4b17023SJohn Marino
316e4b17023SJohn Marino /* Like new_stridx, but for ADDR_EXPR's operand instead. */
317e4b17023SJohn Marino
318e4b17023SJohn Marino static int
new_addr_stridx(tree exp)319e4b17023SJohn Marino new_addr_stridx (tree exp)
320e4b17023SJohn Marino {
321e4b17023SJohn Marino int *pidx;
322e4b17023SJohn Marino if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
323e4b17023SJohn Marino return 0;
324e4b17023SJohn Marino pidx = addr_stridxptr (exp);
325e4b17023SJohn Marino if (pidx != NULL)
326e4b17023SJohn Marino {
327e4b17023SJohn Marino gcc_assert (*pidx == 0);
328e4b17023SJohn Marino *pidx = max_stridx++;
329e4b17023SJohn Marino return *pidx;
330e4b17023SJohn Marino }
331e4b17023SJohn Marino return 0;
332e4b17023SJohn Marino }
333e4b17023SJohn Marino
334e4b17023SJohn Marino /* Create a new strinfo. */
335e4b17023SJohn Marino
336e4b17023SJohn Marino static strinfo
new_strinfo(tree ptr,int idx,tree length)337e4b17023SJohn Marino new_strinfo (tree ptr, int idx, tree length)
338e4b17023SJohn Marino {
339e4b17023SJohn Marino strinfo si = (strinfo) pool_alloc (strinfo_pool);
340e4b17023SJohn Marino si->length = length;
341e4b17023SJohn Marino si->ptr = ptr;
342e4b17023SJohn Marino si->stmt = NULL;
343e4b17023SJohn Marino si->endptr = NULL_TREE;
344e4b17023SJohn Marino si->refcount = 1;
345e4b17023SJohn Marino si->idx = idx;
346e4b17023SJohn Marino si->first = 0;
347e4b17023SJohn Marino si->prev = 0;
348e4b17023SJohn Marino si->next = 0;
349e4b17023SJohn Marino si->writable = false;
350e4b17023SJohn Marino si->dont_invalidate = false;
351e4b17023SJohn Marino return si;
352e4b17023SJohn Marino }
353e4b17023SJohn Marino
354e4b17023SJohn Marino /* Decrease strinfo refcount and free it if not referenced anymore. */
355e4b17023SJohn Marino
356e4b17023SJohn Marino static inline void
free_strinfo(strinfo si)357e4b17023SJohn Marino free_strinfo (strinfo si)
358e4b17023SJohn Marino {
359e4b17023SJohn Marino if (si && --si->refcount == 0)
360e4b17023SJohn Marino pool_free (strinfo_pool, si);
361e4b17023SJohn Marino }
362e4b17023SJohn Marino
363e4b17023SJohn Marino /* Return strinfo vector entry IDX. */
364e4b17023SJohn Marino
365e4b17023SJohn Marino static inline strinfo
get_strinfo(int idx)366e4b17023SJohn Marino get_strinfo (int idx)
367e4b17023SJohn Marino {
368e4b17023SJohn Marino if (VEC_length (strinfo, stridx_to_strinfo) <= (unsigned int) idx)
369e4b17023SJohn Marino return NULL;
370e4b17023SJohn Marino return VEC_index (strinfo, stridx_to_strinfo, idx);
371e4b17023SJohn Marino }
372e4b17023SJohn Marino
373e4b17023SJohn Marino /* Set strinfo in the vector entry IDX to SI. */
374e4b17023SJohn Marino
375e4b17023SJohn Marino static inline void
set_strinfo(int idx,strinfo si)376e4b17023SJohn Marino set_strinfo (int idx, strinfo si)
377e4b17023SJohn Marino {
378e4b17023SJohn Marino if (VEC_length (strinfo, stridx_to_strinfo) && VEC_index (strinfo, stridx_to_strinfo, 0))
379e4b17023SJohn Marino unshare_strinfo_vec ();
380e4b17023SJohn Marino if (VEC_length (strinfo, stridx_to_strinfo) <= (unsigned int) idx)
381e4b17023SJohn Marino VEC_safe_grow_cleared (strinfo, heap, stridx_to_strinfo, idx + 1);
382e4b17023SJohn Marino VEC_replace (strinfo, stridx_to_strinfo, idx, si);
383e4b17023SJohn Marino }
384e4b17023SJohn Marino
385e4b17023SJohn Marino /* Return string length, or NULL if it can't be computed. */
386e4b17023SJohn Marino
387e4b17023SJohn Marino static tree
get_string_length(strinfo si)388e4b17023SJohn Marino get_string_length (strinfo si)
389e4b17023SJohn Marino {
390e4b17023SJohn Marino if (si->length)
391e4b17023SJohn Marino return si->length;
392e4b17023SJohn Marino
393e4b17023SJohn Marino if (si->stmt)
394e4b17023SJohn Marino {
395e4b17023SJohn Marino gimple stmt = si->stmt, lenstmt;
396e4b17023SJohn Marino tree callee, lhs, lhs_var, fn, tem;
397e4b17023SJohn Marino location_t loc;
398e4b17023SJohn Marino gimple_stmt_iterator gsi;
399e4b17023SJohn Marino
400e4b17023SJohn Marino gcc_assert (is_gimple_call (stmt));
401e4b17023SJohn Marino callee = gimple_call_fndecl (stmt);
402e4b17023SJohn Marino gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
403e4b17023SJohn Marino lhs = gimple_call_lhs (stmt);
404e4b17023SJohn Marino gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
405e4b17023SJohn Marino /* unshare_strinfo is intentionally not called here. The (delayed)
406e4b17023SJohn Marino transformation of strcpy or strcat into stpcpy is done at the place
407e4b17023SJohn Marino of the former strcpy/strcat call and so can affect all the strinfos
408e4b17023SJohn Marino with the same stmt. If they were unshared before and transformation
409e4b17023SJohn Marino has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
410e4b17023SJohn Marino just compute the right length. */
411e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (callee))
412e4b17023SJohn Marino {
413e4b17023SJohn Marino case BUILT_IN_STRCAT:
414e4b17023SJohn Marino case BUILT_IN_STRCAT_CHK:
415e4b17023SJohn Marino gsi = gsi_for_stmt (stmt);
416e4b17023SJohn Marino fn = builtin_decl_implicit (BUILT_IN_STRLEN);
417e4b17023SJohn Marino gcc_assert (lhs == NULL_TREE);
418e4b17023SJohn Marino lhs_var = create_tmp_var (TREE_TYPE (TREE_TYPE (fn)), NULL);
419e4b17023SJohn Marino add_referenced_var (lhs_var);
420e4b17023SJohn Marino tem = unshare_expr (gimple_call_arg (stmt, 0));
421e4b17023SJohn Marino lenstmt = gimple_build_call (fn, 1, tem);
422e4b17023SJohn Marino lhs = make_ssa_name (lhs_var, lenstmt);
423e4b17023SJohn Marino gimple_call_set_lhs (lenstmt, lhs);
424e4b17023SJohn Marino gimple_set_vuse (lenstmt, gimple_vuse (stmt));
425e4b17023SJohn Marino gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
426e4b17023SJohn Marino lhs_var = create_tmp_var (TREE_TYPE (gimple_call_arg (stmt, 0)),
427e4b17023SJohn Marino NULL);
428e4b17023SJohn Marino add_referenced_var (lhs_var);
429e4b17023SJohn Marino tem = gimple_call_arg (stmt, 0);
430e4b17023SJohn Marino lenstmt
431e4b17023SJohn Marino = gimple_build_assign_with_ops (POINTER_PLUS_EXPR,
432e4b17023SJohn Marino make_ssa_name (lhs_var, NULL),
433e4b17023SJohn Marino tem, lhs);
434e4b17023SJohn Marino gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
435e4b17023SJohn Marino gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
436e4b17023SJohn Marino lhs = NULL_TREE;
437e4b17023SJohn Marino /* FALLTHRU */
438e4b17023SJohn Marino case BUILT_IN_STRCPY:
439e4b17023SJohn Marino case BUILT_IN_STRCPY_CHK:
440e4b17023SJohn Marino if (gimple_call_num_args (stmt) == 2)
441e4b17023SJohn Marino fn = builtin_decl_implicit (BUILT_IN_STPCPY);
442e4b17023SJohn Marino else
443e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
444e4b17023SJohn Marino gcc_assert (lhs == NULL_TREE);
445e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS) != 0)
446e4b17023SJohn Marino {
447e4b17023SJohn Marino fprintf (dump_file, "Optimizing: ");
448e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
449e4b17023SJohn Marino }
450e4b17023SJohn Marino gimple_call_set_fndecl (stmt, fn);
451e4b17023SJohn Marino lhs_var = create_tmp_var (TREE_TYPE (TREE_TYPE (fn)), NULL);
452e4b17023SJohn Marino add_referenced_var (lhs_var);
453e4b17023SJohn Marino lhs = make_ssa_name (lhs_var, stmt);
454e4b17023SJohn Marino gimple_call_set_lhs (stmt, lhs);
455e4b17023SJohn Marino update_stmt (stmt);
456e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS) != 0)
457e4b17023SJohn Marino {
458e4b17023SJohn Marino fprintf (dump_file, "into: ");
459e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
460e4b17023SJohn Marino }
461e4b17023SJohn Marino /* FALLTHRU */
462e4b17023SJohn Marino case BUILT_IN_STPCPY:
463e4b17023SJohn Marino case BUILT_IN_STPCPY_CHK:
464e4b17023SJohn Marino gcc_assert (lhs != NULL_TREE);
465e4b17023SJohn Marino loc = gimple_location (stmt);
466e4b17023SJohn Marino si->endptr = lhs;
467e4b17023SJohn Marino si->stmt = NULL;
468e4b17023SJohn Marino lhs = fold_convert_loc (loc, size_type_node, lhs);
469e4b17023SJohn Marino si->length = fold_convert_loc (loc, size_type_node, si->ptr);
470e4b17023SJohn Marino si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
471e4b17023SJohn Marino lhs, si->length);
472e4b17023SJohn Marino break;
473e4b17023SJohn Marino default:
474e4b17023SJohn Marino gcc_unreachable ();
475e4b17023SJohn Marino break;
476e4b17023SJohn Marino }
477e4b17023SJohn Marino }
478e4b17023SJohn Marino
479e4b17023SJohn Marino return si->length;
480e4b17023SJohn Marino }
481e4b17023SJohn Marino
482e4b17023SJohn Marino /* Invalidate string length information for strings whose length
483e4b17023SJohn Marino might change due to stores in stmt. */
484e4b17023SJohn Marino
485e4b17023SJohn Marino static bool
maybe_invalidate(gimple stmt)486e4b17023SJohn Marino maybe_invalidate (gimple stmt)
487e4b17023SJohn Marino {
488e4b17023SJohn Marino strinfo si;
489e4b17023SJohn Marino unsigned int i;
490e4b17023SJohn Marino bool nonempty = false;
491e4b17023SJohn Marino
492e4b17023SJohn Marino for (i = 1; VEC_iterate (strinfo, stridx_to_strinfo, i, si); ++i)
493e4b17023SJohn Marino if (si != NULL)
494e4b17023SJohn Marino {
495e4b17023SJohn Marino if (!si->dont_invalidate)
496e4b17023SJohn Marino {
497e4b17023SJohn Marino ao_ref r;
498e4b17023SJohn Marino ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
499e4b17023SJohn Marino if (stmt_may_clobber_ref_p_1 (stmt, &r))
500e4b17023SJohn Marino {
501e4b17023SJohn Marino set_strinfo (i, NULL);
502e4b17023SJohn Marino free_strinfo (si);
503e4b17023SJohn Marino continue;
504e4b17023SJohn Marino }
505e4b17023SJohn Marino }
506e4b17023SJohn Marino si->dont_invalidate = false;
507e4b17023SJohn Marino nonempty = true;
508e4b17023SJohn Marino }
509e4b17023SJohn Marino return nonempty;
510e4b17023SJohn Marino }
511e4b17023SJohn Marino
512e4b17023SJohn Marino /* Unshare strinfo record SI, if it has recount > 1 or
513e4b17023SJohn Marino if stridx_to_strinfo vector is shared with some other
514e4b17023SJohn Marino bbs. */
515e4b17023SJohn Marino
516e4b17023SJohn Marino static strinfo
unshare_strinfo(strinfo si)517e4b17023SJohn Marino unshare_strinfo (strinfo si)
518e4b17023SJohn Marino {
519e4b17023SJohn Marino strinfo nsi;
520e4b17023SJohn Marino
521e4b17023SJohn Marino if (si->refcount == 1 && !strinfo_shared ())
522e4b17023SJohn Marino return si;
523e4b17023SJohn Marino
524e4b17023SJohn Marino nsi = new_strinfo (si->ptr, si->idx, si->length);
525e4b17023SJohn Marino nsi->stmt = si->stmt;
526e4b17023SJohn Marino nsi->endptr = si->endptr;
527e4b17023SJohn Marino nsi->first = si->first;
528e4b17023SJohn Marino nsi->prev = si->prev;
529e4b17023SJohn Marino nsi->next = si->next;
530e4b17023SJohn Marino nsi->writable = si->writable;
531e4b17023SJohn Marino set_strinfo (si->idx, nsi);
532e4b17023SJohn Marino free_strinfo (si);
533e4b17023SJohn Marino return nsi;
534e4b17023SJohn Marino }
535e4b17023SJohn Marino
536e4b17023SJohn Marino /* Return first strinfo in the related strinfo chain
537e4b17023SJohn Marino if all strinfos in between belong to the chain, otherwise
538e4b17023SJohn Marino NULL. */
539e4b17023SJohn Marino
540e4b17023SJohn Marino static strinfo
verify_related_strinfos(strinfo origsi)541e4b17023SJohn Marino verify_related_strinfos (strinfo origsi)
542e4b17023SJohn Marino {
543e4b17023SJohn Marino strinfo si = origsi, psi;
544e4b17023SJohn Marino
545e4b17023SJohn Marino if (origsi->first == 0)
546e4b17023SJohn Marino return NULL;
547e4b17023SJohn Marino for (; si->prev; si = psi)
548e4b17023SJohn Marino {
549e4b17023SJohn Marino if (si->first != origsi->first)
550e4b17023SJohn Marino return NULL;
551e4b17023SJohn Marino psi = get_strinfo (si->prev);
552e4b17023SJohn Marino if (psi == NULL)
553e4b17023SJohn Marino return NULL;
554e4b17023SJohn Marino if (psi->next != si->idx)
555e4b17023SJohn Marino return NULL;
556e4b17023SJohn Marino }
557e4b17023SJohn Marino if (si->idx != si->first)
558e4b17023SJohn Marino return NULL;
559e4b17023SJohn Marino return si;
560e4b17023SJohn Marino }
561e4b17023SJohn Marino
562e4b17023SJohn Marino /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
563e4b17023SJohn Marino to a zero-length string and if possible chain it to a related strinfo
564e4b17023SJohn Marino chain whose part is or might be CHAINSI. */
565e4b17023SJohn Marino
566e4b17023SJohn Marino static strinfo
zero_length_string(tree ptr,strinfo chainsi)567e4b17023SJohn Marino zero_length_string (tree ptr, strinfo chainsi)
568e4b17023SJohn Marino {
569e4b17023SJohn Marino strinfo si;
570e4b17023SJohn Marino int idx;
571e4b17023SJohn Marino gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
572e4b17023SJohn Marino && get_stridx (ptr) == 0);
573e4b17023SJohn Marino
574e4b17023SJohn Marino if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
575e4b17023SJohn Marino return NULL;
576e4b17023SJohn Marino if (chainsi != NULL)
577e4b17023SJohn Marino {
578e4b17023SJohn Marino si = verify_related_strinfos (chainsi);
579e4b17023SJohn Marino if (si)
580e4b17023SJohn Marino {
581e4b17023SJohn Marino chainsi = si;
582e4b17023SJohn Marino for (; chainsi->next; chainsi = si)
583e4b17023SJohn Marino {
584e4b17023SJohn Marino if (chainsi->endptr == NULL_TREE)
585e4b17023SJohn Marino {
586e4b17023SJohn Marino chainsi = unshare_strinfo (chainsi);
587e4b17023SJohn Marino chainsi->endptr = ptr;
588e4b17023SJohn Marino }
589e4b17023SJohn Marino si = get_strinfo (chainsi->next);
590e4b17023SJohn Marino if (si == NULL
591e4b17023SJohn Marino || si->first != chainsi->first
592e4b17023SJohn Marino || si->prev != chainsi->idx)
593e4b17023SJohn Marino break;
594e4b17023SJohn Marino }
595e4b17023SJohn Marino gcc_assert (chainsi->length || chainsi->stmt);
596e4b17023SJohn Marino if (chainsi->endptr == NULL_TREE)
597e4b17023SJohn Marino {
598e4b17023SJohn Marino chainsi = unshare_strinfo (chainsi);
599e4b17023SJohn Marino chainsi->endptr = ptr;
600e4b17023SJohn Marino }
601e4b17023SJohn Marino if (chainsi->length && integer_zerop (chainsi->length))
602e4b17023SJohn Marino {
603e4b17023SJohn Marino if (chainsi->next)
604e4b17023SJohn Marino {
605e4b17023SJohn Marino chainsi = unshare_strinfo (chainsi);
606e4b17023SJohn Marino chainsi->next = 0;
607e4b17023SJohn Marino }
608e4b17023SJohn Marino VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (ptr),
609e4b17023SJohn Marino chainsi->idx);
610e4b17023SJohn Marino return chainsi;
611e4b17023SJohn Marino }
612e4b17023SJohn Marino }
613e4b17023SJohn Marino else if (chainsi->first || chainsi->prev || chainsi->next)
614e4b17023SJohn Marino {
615e4b17023SJohn Marino chainsi = unshare_strinfo (chainsi);
616e4b17023SJohn Marino chainsi->first = 0;
617e4b17023SJohn Marino chainsi->prev = 0;
618e4b17023SJohn Marino chainsi->next = 0;
619e4b17023SJohn Marino }
620e4b17023SJohn Marino }
621e4b17023SJohn Marino idx = new_stridx (ptr);
622e4b17023SJohn Marino if (idx == 0)
623e4b17023SJohn Marino return NULL;
624e4b17023SJohn Marino si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0));
625e4b17023SJohn Marino set_strinfo (idx, si);
626e4b17023SJohn Marino si->endptr = ptr;
627e4b17023SJohn Marino if (chainsi != NULL)
628e4b17023SJohn Marino {
629e4b17023SJohn Marino chainsi = unshare_strinfo (chainsi);
630e4b17023SJohn Marino if (chainsi->first == 0)
631e4b17023SJohn Marino chainsi->first = chainsi->idx;
632e4b17023SJohn Marino chainsi->next = idx;
633e4b17023SJohn Marino if (chainsi->endptr == NULL_TREE)
634e4b17023SJohn Marino chainsi->endptr = ptr;
635e4b17023SJohn Marino si->prev = chainsi->idx;
636e4b17023SJohn Marino si->first = chainsi->first;
637e4b17023SJohn Marino si->writable = chainsi->writable;
638e4b17023SJohn Marino }
639e4b17023SJohn Marino return si;
640e4b17023SJohn Marino }
641e4b17023SJohn Marino
642e4b17023SJohn Marino /* For strinfo ORIGSI whose length has been just updated
643e4b17023SJohn Marino update also related strinfo lengths (add ADJ to each,
644e4b17023SJohn Marino but don't adjust ORIGSI). */
645e4b17023SJohn Marino
646e4b17023SJohn Marino static void
adjust_related_strinfos(location_t loc,strinfo origsi,tree adj)647e4b17023SJohn Marino adjust_related_strinfos (location_t loc, strinfo origsi, tree adj)
648e4b17023SJohn Marino {
649e4b17023SJohn Marino strinfo si = verify_related_strinfos (origsi);
650e4b17023SJohn Marino
651e4b17023SJohn Marino if (si == NULL)
652e4b17023SJohn Marino return;
653e4b17023SJohn Marino
654e4b17023SJohn Marino while (1)
655e4b17023SJohn Marino {
656e4b17023SJohn Marino strinfo nsi;
657e4b17023SJohn Marino
658e4b17023SJohn Marino if (si != origsi)
659e4b17023SJohn Marino {
660e4b17023SJohn Marino tree tem;
661e4b17023SJohn Marino
662e4b17023SJohn Marino si = unshare_strinfo (si);
663e4b17023SJohn Marino if (si->length)
664e4b17023SJohn Marino {
665e4b17023SJohn Marino tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
666e4b17023SJohn Marino si->length = fold_build2_loc (loc, PLUS_EXPR,
667e4b17023SJohn Marino TREE_TYPE (si->length), si->length,
668e4b17023SJohn Marino tem);
669e4b17023SJohn Marino }
670e4b17023SJohn Marino else if (si->stmt != NULL)
671e4b17023SJohn Marino /* Delayed length computation is unaffected. */
672e4b17023SJohn Marino ;
673e4b17023SJohn Marino else
674e4b17023SJohn Marino gcc_unreachable ();
675e4b17023SJohn Marino
676e4b17023SJohn Marino si->endptr = NULL_TREE;
677e4b17023SJohn Marino si->dont_invalidate = true;
678e4b17023SJohn Marino }
679e4b17023SJohn Marino if (si->next == 0)
680e4b17023SJohn Marino return;
681e4b17023SJohn Marino nsi = get_strinfo (si->next);
682e4b17023SJohn Marino if (nsi == NULL
683e4b17023SJohn Marino || nsi->first != si->first
684e4b17023SJohn Marino || nsi->prev != si->idx)
685e4b17023SJohn Marino return;
686e4b17023SJohn Marino si = nsi;
687e4b17023SJohn Marino }
688e4b17023SJohn Marino }
689e4b17023SJohn Marino
690e4b17023SJohn Marino /* Find if there are other SSA_NAME pointers equal to PTR
691e4b17023SJohn Marino for which we don't track their string lengths yet. If so, use
692e4b17023SJohn Marino IDX for them. */
693e4b17023SJohn Marino
694e4b17023SJohn Marino static void
find_equal_ptrs(tree ptr,int idx)695e4b17023SJohn Marino find_equal_ptrs (tree ptr, int idx)
696e4b17023SJohn Marino {
697e4b17023SJohn Marino if (TREE_CODE (ptr) != SSA_NAME)
698e4b17023SJohn Marino return;
699e4b17023SJohn Marino while (1)
700e4b17023SJohn Marino {
701e4b17023SJohn Marino gimple stmt = SSA_NAME_DEF_STMT (ptr);
702e4b17023SJohn Marino if (!is_gimple_assign (stmt))
703e4b17023SJohn Marino return;
704e4b17023SJohn Marino ptr = gimple_assign_rhs1 (stmt);
705e4b17023SJohn Marino switch (gimple_assign_rhs_code (stmt))
706e4b17023SJohn Marino {
707e4b17023SJohn Marino case SSA_NAME:
708e4b17023SJohn Marino break;
709e4b17023SJohn Marino CASE_CONVERT:
710e4b17023SJohn Marino if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
711e4b17023SJohn Marino return;
712e4b17023SJohn Marino if (TREE_CODE (ptr) == SSA_NAME)
713e4b17023SJohn Marino break;
714e4b17023SJohn Marino if (TREE_CODE (ptr) != ADDR_EXPR)
715e4b17023SJohn Marino return;
716e4b17023SJohn Marino /* FALLTHRU */
717e4b17023SJohn Marino case ADDR_EXPR:
718e4b17023SJohn Marino {
719e4b17023SJohn Marino int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
720e4b17023SJohn Marino if (pidx != NULL && *pidx == 0)
721e4b17023SJohn Marino *pidx = idx;
722e4b17023SJohn Marino return;
723e4b17023SJohn Marino }
724e4b17023SJohn Marino default:
725e4b17023SJohn Marino return;
726e4b17023SJohn Marino }
727e4b17023SJohn Marino
728e4b17023SJohn Marino /* We might find an endptr created in this pass. Grow the
729e4b17023SJohn Marino vector in that case. */
730e4b17023SJohn Marino if (VEC_length (int, ssa_ver_to_stridx) <= SSA_NAME_VERSION (ptr))
731e4b17023SJohn Marino VEC_safe_grow_cleared (int, heap, ssa_ver_to_stridx, num_ssa_names);
732e4b17023SJohn Marino
733e4b17023SJohn Marino if (VEC_index (int, ssa_ver_to_stridx, SSA_NAME_VERSION (ptr)) != 0)
734e4b17023SJohn Marino return;
735e4b17023SJohn Marino VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (ptr), idx);
736e4b17023SJohn Marino }
737e4b17023SJohn Marino }
738e4b17023SJohn Marino
739e4b17023SJohn Marino /* If the last .MEM setter statement before STMT is
740e4b17023SJohn Marino memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
741e4b17023SJohn Marino and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
742e4b17023SJohn Marino just memcpy (x, y, strlen (y)). SI must be the zero length
743e4b17023SJohn Marino strinfo. */
744e4b17023SJohn Marino
745e4b17023SJohn Marino static void
adjust_last_stmt(strinfo si,gimple stmt,bool is_strcat)746e4b17023SJohn Marino adjust_last_stmt (strinfo si, gimple stmt, bool is_strcat)
747e4b17023SJohn Marino {
748e4b17023SJohn Marino tree vuse, callee, len;
749e4b17023SJohn Marino struct laststmt_struct last = laststmt;
750e4b17023SJohn Marino strinfo lastsi, firstsi;
751e4b17023SJohn Marino
752e4b17023SJohn Marino laststmt.stmt = NULL;
753e4b17023SJohn Marino laststmt.len = NULL_TREE;
754e4b17023SJohn Marino laststmt.stridx = 0;
755e4b17023SJohn Marino
756e4b17023SJohn Marino if (last.stmt == NULL)
757e4b17023SJohn Marino return;
758e4b17023SJohn Marino
759e4b17023SJohn Marino vuse = gimple_vuse (stmt);
760e4b17023SJohn Marino if (vuse == NULL_TREE
761e4b17023SJohn Marino || SSA_NAME_DEF_STMT (vuse) != last.stmt
762e4b17023SJohn Marino || !has_single_use (vuse))
763e4b17023SJohn Marino return;
764e4b17023SJohn Marino
765e4b17023SJohn Marino gcc_assert (last.stridx > 0);
766e4b17023SJohn Marino lastsi = get_strinfo (last.stridx);
767e4b17023SJohn Marino if (lastsi == NULL)
768e4b17023SJohn Marino return;
769e4b17023SJohn Marino
770e4b17023SJohn Marino if (lastsi != si)
771e4b17023SJohn Marino {
772e4b17023SJohn Marino if (lastsi->first == 0 || lastsi->first != si->first)
773e4b17023SJohn Marino return;
774e4b17023SJohn Marino
775e4b17023SJohn Marino firstsi = verify_related_strinfos (si);
776e4b17023SJohn Marino if (firstsi == NULL)
777e4b17023SJohn Marino return;
778e4b17023SJohn Marino while (firstsi != lastsi)
779e4b17023SJohn Marino {
780e4b17023SJohn Marino strinfo nextsi;
781e4b17023SJohn Marino if (firstsi->next == 0)
782e4b17023SJohn Marino return;
783e4b17023SJohn Marino nextsi = get_strinfo (firstsi->next);
784e4b17023SJohn Marino if (nextsi == NULL
785e4b17023SJohn Marino || nextsi->prev != firstsi->idx
786e4b17023SJohn Marino || nextsi->first != si->first)
787e4b17023SJohn Marino return;
788e4b17023SJohn Marino firstsi = nextsi;
789e4b17023SJohn Marino }
790e4b17023SJohn Marino }
791e4b17023SJohn Marino
792e4b17023SJohn Marino if (!is_strcat)
793e4b17023SJohn Marino {
794e4b17023SJohn Marino if (si->length == NULL_TREE || !integer_zerop (si->length))
795e4b17023SJohn Marino return;
796e4b17023SJohn Marino }
797e4b17023SJohn Marino
798e4b17023SJohn Marino if (is_gimple_assign (last.stmt))
799e4b17023SJohn Marino {
800e4b17023SJohn Marino gimple_stmt_iterator gsi;
801e4b17023SJohn Marino
802e4b17023SJohn Marino if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
803e4b17023SJohn Marino return;
804e4b17023SJohn Marino if (stmt_could_throw_p (last.stmt))
805e4b17023SJohn Marino return;
806e4b17023SJohn Marino gsi = gsi_for_stmt (last.stmt);
807e4b17023SJohn Marino unlink_stmt_vdef (last.stmt);
808e4b17023SJohn Marino release_defs (last.stmt);
809e4b17023SJohn Marino gsi_remove (&gsi, true);
810e4b17023SJohn Marino return;
811e4b17023SJohn Marino }
812e4b17023SJohn Marino
813e4b17023SJohn Marino if (!is_gimple_call (last.stmt))
814e4b17023SJohn Marino return;
8155ce9237cSJohn Marino if (!gimple_call_builtin_class_p (last.stmt, BUILT_IN_NORMAL))
816e4b17023SJohn Marino return;
817e4b17023SJohn Marino
8185ce9237cSJohn Marino callee = gimple_call_fndecl (last.stmt);
819e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (callee))
820e4b17023SJohn Marino {
821e4b17023SJohn Marino case BUILT_IN_MEMCPY:
822e4b17023SJohn Marino case BUILT_IN_MEMCPY_CHK:
823e4b17023SJohn Marino break;
824e4b17023SJohn Marino default:
825e4b17023SJohn Marino return;
826e4b17023SJohn Marino }
827e4b17023SJohn Marino
828e4b17023SJohn Marino len = gimple_call_arg (last.stmt, 2);
829e4b17023SJohn Marino if (host_integerp (len, 1))
830e4b17023SJohn Marino {
831e4b17023SJohn Marino if (!host_integerp (last.len, 1)
832e4b17023SJohn Marino || integer_zerop (len)
833e4b17023SJohn Marino || (unsigned HOST_WIDE_INT) tree_low_cst (len, 1)
834e4b17023SJohn Marino != (unsigned HOST_WIDE_INT) tree_low_cst (last.len, 1) + 1)
835e4b17023SJohn Marino return;
836e4b17023SJohn Marino /* Don't adjust the length if it is divisible by 4, it is more efficient
837e4b17023SJohn Marino to store the extra '\0' in that case. */
838e4b17023SJohn Marino if ((((unsigned HOST_WIDE_INT) tree_low_cst (len, 1)) & 3) == 0)
839e4b17023SJohn Marino return;
840e4b17023SJohn Marino }
841e4b17023SJohn Marino else if (TREE_CODE (len) == SSA_NAME)
842e4b17023SJohn Marino {
843e4b17023SJohn Marino gimple def_stmt = SSA_NAME_DEF_STMT (len);
844e4b17023SJohn Marino if (!is_gimple_assign (def_stmt)
845e4b17023SJohn Marino || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
846e4b17023SJohn Marino || gimple_assign_rhs1 (def_stmt) != last.len
847e4b17023SJohn Marino || !integer_onep (gimple_assign_rhs2 (def_stmt)))
848e4b17023SJohn Marino return;
849e4b17023SJohn Marino }
850e4b17023SJohn Marino else
851e4b17023SJohn Marino return;
852e4b17023SJohn Marino
853e4b17023SJohn Marino gimple_call_set_arg (last.stmt, 2, last.len);
854e4b17023SJohn Marino update_stmt (last.stmt);
855e4b17023SJohn Marino }
856e4b17023SJohn Marino
857e4b17023SJohn Marino /* Handle a strlen call. If strlen of the argument is known, replace
858e4b17023SJohn Marino the strlen call with the known value, otherwise remember that strlen
859e4b17023SJohn Marino of the argument is stored in the lhs SSA_NAME. */
860e4b17023SJohn Marino
861e4b17023SJohn Marino static void
handle_builtin_strlen(gimple_stmt_iterator * gsi)862e4b17023SJohn Marino handle_builtin_strlen (gimple_stmt_iterator *gsi)
863e4b17023SJohn Marino {
864e4b17023SJohn Marino int idx;
865e4b17023SJohn Marino tree src;
866e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi);
867e4b17023SJohn Marino tree lhs = gimple_call_lhs (stmt);
868e4b17023SJohn Marino
869e4b17023SJohn Marino if (lhs == NULL_TREE)
870e4b17023SJohn Marino return;
871e4b17023SJohn Marino
872e4b17023SJohn Marino src = gimple_call_arg (stmt, 0);
873e4b17023SJohn Marino idx = get_stridx (src);
874e4b17023SJohn Marino if (idx)
875e4b17023SJohn Marino {
876e4b17023SJohn Marino strinfo si = NULL;
877e4b17023SJohn Marino tree rhs;
878e4b17023SJohn Marino
879e4b17023SJohn Marino if (idx < 0)
880e4b17023SJohn Marino rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
881e4b17023SJohn Marino else
882e4b17023SJohn Marino {
883e4b17023SJohn Marino rhs = NULL_TREE;
884e4b17023SJohn Marino si = get_strinfo (idx);
885e4b17023SJohn Marino if (si != NULL)
886e4b17023SJohn Marino rhs = get_string_length (si);
887e4b17023SJohn Marino }
888e4b17023SJohn Marino if (rhs != NULL_TREE)
889e4b17023SJohn Marino {
890e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS) != 0)
891e4b17023SJohn Marino {
892e4b17023SJohn Marino fprintf (dump_file, "Optimizing: ");
893e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
894e4b17023SJohn Marino }
895e4b17023SJohn Marino rhs = unshare_expr (rhs);
896e4b17023SJohn Marino if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
897e4b17023SJohn Marino rhs = fold_convert_loc (gimple_location (stmt),
898e4b17023SJohn Marino TREE_TYPE (lhs), rhs);
899e4b17023SJohn Marino if (!update_call_from_tree (gsi, rhs))
900e4b17023SJohn Marino gimplify_and_update_call_from_tree (gsi, rhs);
901e4b17023SJohn Marino stmt = gsi_stmt (*gsi);
902e4b17023SJohn Marino update_stmt (stmt);
903e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS) != 0)
904e4b17023SJohn Marino {
905e4b17023SJohn Marino fprintf (dump_file, "into: ");
906e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
907e4b17023SJohn Marino }
908e4b17023SJohn Marino if (si != NULL
909e4b17023SJohn Marino && TREE_CODE (si->length) != SSA_NAME
910e4b17023SJohn Marino && TREE_CODE (si->length) != INTEGER_CST
911e4b17023SJohn Marino && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
912e4b17023SJohn Marino {
913e4b17023SJohn Marino si = unshare_strinfo (si);
914e4b17023SJohn Marino si->length = lhs;
915e4b17023SJohn Marino }
916e4b17023SJohn Marino return;
917e4b17023SJohn Marino }
918e4b17023SJohn Marino }
919e4b17023SJohn Marino if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
920e4b17023SJohn Marino return;
921e4b17023SJohn Marino if (idx == 0)
922e4b17023SJohn Marino idx = new_stridx (src);
923e4b17023SJohn Marino else if (get_strinfo (idx) != NULL)
924e4b17023SJohn Marino return;
925e4b17023SJohn Marino if (idx)
926e4b17023SJohn Marino {
927e4b17023SJohn Marino strinfo si = new_strinfo (src, idx, lhs);
928e4b17023SJohn Marino set_strinfo (idx, si);
929e4b17023SJohn Marino find_equal_ptrs (src, idx);
930e4b17023SJohn Marino }
931e4b17023SJohn Marino }
932e4b17023SJohn Marino
933e4b17023SJohn Marino /* Handle a strchr call. If strlen of the first argument is known, replace
934e4b17023SJohn Marino the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
935e4b17023SJohn Marino that lhs of the call is endptr and strlen of the argument is endptr - x. */
936e4b17023SJohn Marino
937e4b17023SJohn Marino static void
handle_builtin_strchr(gimple_stmt_iterator * gsi)938e4b17023SJohn Marino handle_builtin_strchr (gimple_stmt_iterator *gsi)
939e4b17023SJohn Marino {
940e4b17023SJohn Marino int idx;
941e4b17023SJohn Marino tree src;
942e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi);
943e4b17023SJohn Marino tree lhs = gimple_call_lhs (stmt);
944e4b17023SJohn Marino
945e4b17023SJohn Marino if (lhs == NULL_TREE)
946e4b17023SJohn Marino return;
947e4b17023SJohn Marino
948e4b17023SJohn Marino if (!integer_zerop (gimple_call_arg (stmt, 1)))
949e4b17023SJohn Marino return;
950e4b17023SJohn Marino
951e4b17023SJohn Marino src = gimple_call_arg (stmt, 0);
952e4b17023SJohn Marino idx = get_stridx (src);
953e4b17023SJohn Marino if (idx)
954e4b17023SJohn Marino {
955e4b17023SJohn Marino strinfo si = NULL;
956e4b17023SJohn Marino tree rhs;
957e4b17023SJohn Marino
958e4b17023SJohn Marino if (idx < 0)
959e4b17023SJohn Marino rhs = build_int_cst (size_type_node, ~idx);
960e4b17023SJohn Marino else
961e4b17023SJohn Marino {
962e4b17023SJohn Marino rhs = NULL_TREE;
963e4b17023SJohn Marino si = get_strinfo (idx);
964e4b17023SJohn Marino if (si != NULL)
965e4b17023SJohn Marino rhs = get_string_length (si);
966e4b17023SJohn Marino }
967e4b17023SJohn Marino if (rhs != NULL_TREE)
968e4b17023SJohn Marino {
969e4b17023SJohn Marino location_t loc = gimple_location (stmt);
970e4b17023SJohn Marino
971e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS) != 0)
972e4b17023SJohn Marino {
973e4b17023SJohn Marino fprintf (dump_file, "Optimizing: ");
974e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
975e4b17023SJohn Marino }
976e4b17023SJohn Marino if (si != NULL && si->endptr != NULL_TREE)
977e4b17023SJohn Marino {
978e4b17023SJohn Marino rhs = unshare_expr (si->endptr);
979e4b17023SJohn Marino if (!useless_type_conversion_p (TREE_TYPE (lhs),
980e4b17023SJohn Marino TREE_TYPE (rhs)))
981e4b17023SJohn Marino rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
982e4b17023SJohn Marino }
983e4b17023SJohn Marino else
984e4b17023SJohn Marino {
985e4b17023SJohn Marino rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
986e4b17023SJohn Marino rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
987e4b17023SJohn Marino TREE_TYPE (src), src, rhs);
988e4b17023SJohn Marino if (!useless_type_conversion_p (TREE_TYPE (lhs),
989e4b17023SJohn Marino TREE_TYPE (rhs)))
990e4b17023SJohn Marino rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
991e4b17023SJohn Marino }
992e4b17023SJohn Marino if (!update_call_from_tree (gsi, rhs))
993e4b17023SJohn Marino gimplify_and_update_call_from_tree (gsi, rhs);
994e4b17023SJohn Marino stmt = gsi_stmt (*gsi);
995e4b17023SJohn Marino update_stmt (stmt);
996e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS) != 0)
997e4b17023SJohn Marino {
998e4b17023SJohn Marino fprintf (dump_file, "into: ");
999e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1000e4b17023SJohn Marino }
1001e4b17023SJohn Marino if (si != NULL
1002e4b17023SJohn Marino && si->endptr == NULL_TREE
1003e4b17023SJohn Marino && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1004e4b17023SJohn Marino {
1005e4b17023SJohn Marino si = unshare_strinfo (si);
1006e4b17023SJohn Marino si->endptr = lhs;
1007e4b17023SJohn Marino }
1008e4b17023SJohn Marino zero_length_string (lhs, si);
1009e4b17023SJohn Marino return;
1010e4b17023SJohn Marino }
1011e4b17023SJohn Marino }
1012e4b17023SJohn Marino if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1013e4b17023SJohn Marino return;
1014e4b17023SJohn Marino if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1015e4b17023SJohn Marino {
1016e4b17023SJohn Marino if (idx == 0)
1017e4b17023SJohn Marino idx = new_stridx (src);
1018e4b17023SJohn Marino else if (get_strinfo (idx) != NULL)
1019e4b17023SJohn Marino {
1020e4b17023SJohn Marino zero_length_string (lhs, NULL);
1021e4b17023SJohn Marino return;
1022e4b17023SJohn Marino }
1023e4b17023SJohn Marino if (idx)
1024e4b17023SJohn Marino {
1025e4b17023SJohn Marino location_t loc = gimple_location (stmt);
1026e4b17023SJohn Marino tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1027e4b17023SJohn Marino tree srcu = fold_convert_loc (loc, size_type_node, src);
1028e4b17023SJohn Marino tree length = fold_build2_loc (loc, MINUS_EXPR,
1029e4b17023SJohn Marino size_type_node, lhsu, srcu);
1030e4b17023SJohn Marino strinfo si = new_strinfo (src, idx, length);
1031e4b17023SJohn Marino si->endptr = lhs;
1032e4b17023SJohn Marino set_strinfo (idx, si);
1033e4b17023SJohn Marino find_equal_ptrs (src, idx);
1034e4b17023SJohn Marino zero_length_string (lhs, si);
1035e4b17023SJohn Marino }
1036e4b17023SJohn Marino }
1037e4b17023SJohn Marino else
1038e4b17023SJohn Marino zero_length_string (lhs, NULL);
1039e4b17023SJohn Marino }
1040e4b17023SJohn Marino
1041e4b17023SJohn Marino /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1042e4b17023SJohn Marino If strlen of the second argument is known, strlen of the first argument
1043e4b17023SJohn Marino is the same after this call. Furthermore, attempt to convert it to
1044e4b17023SJohn Marino memcpy. */
1045e4b17023SJohn Marino
1046e4b17023SJohn Marino static void
handle_builtin_strcpy(enum built_in_function bcode,gimple_stmt_iterator * gsi)1047e4b17023SJohn Marino handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1048e4b17023SJohn Marino {
1049e4b17023SJohn Marino int idx, didx;
1050e4b17023SJohn Marino tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1051e4b17023SJohn Marino bool success;
1052e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi);
1053e4b17023SJohn Marino strinfo si, dsi, olddsi, zsi;
1054e4b17023SJohn Marino location_t loc;
1055e4b17023SJohn Marino
1056e4b17023SJohn Marino src = gimple_call_arg (stmt, 1);
1057e4b17023SJohn Marino dst = gimple_call_arg (stmt, 0);
1058e4b17023SJohn Marino lhs = gimple_call_lhs (stmt);
1059e4b17023SJohn Marino idx = get_stridx (src);
1060e4b17023SJohn Marino si = NULL;
1061e4b17023SJohn Marino if (idx > 0)
1062e4b17023SJohn Marino si = get_strinfo (idx);
1063e4b17023SJohn Marino
1064e4b17023SJohn Marino didx = get_stridx (dst);
1065e4b17023SJohn Marino olddsi = NULL;
1066e4b17023SJohn Marino oldlen = NULL_TREE;
1067e4b17023SJohn Marino if (didx > 0)
1068e4b17023SJohn Marino olddsi = get_strinfo (didx);
1069e4b17023SJohn Marino else if (didx < 0)
1070e4b17023SJohn Marino return;
1071e4b17023SJohn Marino
1072e4b17023SJohn Marino if (olddsi != NULL)
1073e4b17023SJohn Marino adjust_last_stmt (olddsi, stmt, false);
1074e4b17023SJohn Marino
1075e4b17023SJohn Marino srclen = NULL_TREE;
1076e4b17023SJohn Marino if (si != NULL)
1077e4b17023SJohn Marino srclen = get_string_length (si);
1078e4b17023SJohn Marino else if (idx < 0)
1079e4b17023SJohn Marino srclen = build_int_cst (size_type_node, ~idx);
1080e4b17023SJohn Marino
1081e4b17023SJohn Marino loc = gimple_location (stmt);
1082e4b17023SJohn Marino if (srclen == NULL_TREE)
1083e4b17023SJohn Marino switch (bcode)
1084e4b17023SJohn Marino {
1085e4b17023SJohn Marino case BUILT_IN_STRCPY:
1086e4b17023SJohn Marino case BUILT_IN_STRCPY_CHK:
1087e4b17023SJohn Marino if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1088e4b17023SJohn Marino return;
1089e4b17023SJohn Marino break;
1090e4b17023SJohn Marino case BUILT_IN_STPCPY:
1091e4b17023SJohn Marino case BUILT_IN_STPCPY_CHK:
1092e4b17023SJohn Marino if (lhs == NULL_TREE)
1093e4b17023SJohn Marino return;
1094e4b17023SJohn Marino else
1095e4b17023SJohn Marino {
1096e4b17023SJohn Marino tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1097e4b17023SJohn Marino srclen = fold_convert_loc (loc, size_type_node, dst);
1098e4b17023SJohn Marino srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1099e4b17023SJohn Marino lhsuint, srclen);
1100e4b17023SJohn Marino }
1101e4b17023SJohn Marino break;
1102e4b17023SJohn Marino default:
1103e4b17023SJohn Marino gcc_unreachable ();
1104e4b17023SJohn Marino }
1105e4b17023SJohn Marino
1106e4b17023SJohn Marino if (didx == 0)
1107e4b17023SJohn Marino {
1108e4b17023SJohn Marino didx = new_stridx (dst);
1109e4b17023SJohn Marino if (didx == 0)
1110e4b17023SJohn Marino return;
1111e4b17023SJohn Marino }
1112e4b17023SJohn Marino if (olddsi != NULL)
1113e4b17023SJohn Marino {
1114e4b17023SJohn Marino oldlen = olddsi->length;
1115e4b17023SJohn Marino dsi = unshare_strinfo (olddsi);
1116e4b17023SJohn Marino dsi->length = srclen;
1117e4b17023SJohn Marino /* Break the chain, so adjust_related_strinfo on later pointers in
1118e4b17023SJohn Marino the chain won't adjust this one anymore. */
1119e4b17023SJohn Marino dsi->next = 0;
1120e4b17023SJohn Marino dsi->stmt = NULL;
1121e4b17023SJohn Marino dsi->endptr = NULL_TREE;
1122e4b17023SJohn Marino }
1123e4b17023SJohn Marino else
1124e4b17023SJohn Marino {
1125e4b17023SJohn Marino dsi = new_strinfo (dst, didx, srclen);
1126e4b17023SJohn Marino set_strinfo (didx, dsi);
1127e4b17023SJohn Marino find_equal_ptrs (dst, didx);
1128e4b17023SJohn Marino }
1129e4b17023SJohn Marino dsi->writable = true;
1130e4b17023SJohn Marino dsi->dont_invalidate = true;
1131e4b17023SJohn Marino
1132e4b17023SJohn Marino if (dsi->length == NULL_TREE)
1133e4b17023SJohn Marino {
1134e4b17023SJohn Marino strinfo chainsi;
1135e4b17023SJohn Marino
1136e4b17023SJohn Marino /* If string length of src is unknown, use delayed length
1137e4b17023SJohn Marino computation. If string lenth of dst will be needed, it
1138e4b17023SJohn Marino can be computed by transforming this strcpy call into
1139e4b17023SJohn Marino stpcpy and subtracting dst from the return value. */
1140e4b17023SJohn Marino
1141e4b17023SJohn Marino /* Look for earlier strings whose length could be determined if
1142e4b17023SJohn Marino this strcpy is turned into an stpcpy. */
1143e4b17023SJohn Marino
1144e4b17023SJohn Marino if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1145e4b17023SJohn Marino {
1146e4b17023SJohn Marino for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1147e4b17023SJohn Marino {
1148e4b17023SJohn Marino /* When setting a stmt for delayed length computation
1149e4b17023SJohn Marino prevent all strinfos through dsi from being
1150e4b17023SJohn Marino invalidated. */
1151e4b17023SJohn Marino chainsi = unshare_strinfo (chainsi);
1152e4b17023SJohn Marino chainsi->stmt = stmt;
1153e4b17023SJohn Marino chainsi->length = NULL_TREE;
1154e4b17023SJohn Marino chainsi->endptr = NULL_TREE;
1155e4b17023SJohn Marino chainsi->dont_invalidate = true;
1156e4b17023SJohn Marino }
1157e4b17023SJohn Marino }
1158e4b17023SJohn Marino dsi->stmt = stmt;
1159e4b17023SJohn Marino return;
1160e4b17023SJohn Marino }
1161e4b17023SJohn Marino
1162e4b17023SJohn Marino if (olddsi != NULL)
1163e4b17023SJohn Marino {
1164e4b17023SJohn Marino tree adj = NULL_TREE;
1165e4b17023SJohn Marino if (oldlen == NULL_TREE)
1166e4b17023SJohn Marino ;
1167e4b17023SJohn Marino else if (integer_zerop (oldlen))
1168e4b17023SJohn Marino adj = srclen;
1169e4b17023SJohn Marino else if (TREE_CODE (oldlen) == INTEGER_CST
1170e4b17023SJohn Marino || TREE_CODE (srclen) == INTEGER_CST)
1171e4b17023SJohn Marino adj = fold_build2_loc (loc, MINUS_EXPR,
1172e4b17023SJohn Marino TREE_TYPE (srclen), srclen,
1173e4b17023SJohn Marino fold_convert_loc (loc, TREE_TYPE (srclen),
1174e4b17023SJohn Marino oldlen));
1175e4b17023SJohn Marino if (adj != NULL_TREE)
1176e4b17023SJohn Marino adjust_related_strinfos (loc, dsi, adj);
1177e4b17023SJohn Marino else
1178e4b17023SJohn Marino dsi->prev = 0;
1179e4b17023SJohn Marino }
1180e4b17023SJohn Marino /* strcpy src may not overlap dst, so src doesn't need to be
1181e4b17023SJohn Marino invalidated either. */
1182e4b17023SJohn Marino if (si != NULL)
1183e4b17023SJohn Marino si->dont_invalidate = true;
1184e4b17023SJohn Marino
1185e4b17023SJohn Marino fn = NULL_TREE;
1186e4b17023SJohn Marino zsi = NULL;
1187e4b17023SJohn Marino switch (bcode)
1188e4b17023SJohn Marino {
1189e4b17023SJohn Marino case BUILT_IN_STRCPY:
1190e4b17023SJohn Marino fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1191e4b17023SJohn Marino if (lhs)
1192e4b17023SJohn Marino VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (lhs), didx);
1193e4b17023SJohn Marino break;
1194e4b17023SJohn Marino case BUILT_IN_STRCPY_CHK:
1195e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1196e4b17023SJohn Marino if (lhs)
1197e4b17023SJohn Marino VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (lhs), didx);
1198e4b17023SJohn Marino break;
1199e4b17023SJohn Marino case BUILT_IN_STPCPY:
1200e4b17023SJohn Marino /* This would need adjustment of the lhs (subtract one),
1201e4b17023SJohn Marino or detection that the trailing '\0' doesn't need to be
1202e4b17023SJohn Marino written, if it will be immediately overwritten.
1203e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1204e4b17023SJohn Marino if (lhs)
1205e4b17023SJohn Marino {
1206e4b17023SJohn Marino dsi->endptr = lhs;
1207e4b17023SJohn Marino zsi = zero_length_string (lhs, dsi);
1208e4b17023SJohn Marino }
1209e4b17023SJohn Marino break;
1210e4b17023SJohn Marino case BUILT_IN_STPCPY_CHK:
1211e4b17023SJohn Marino /* This would need adjustment of the lhs (subtract one),
1212e4b17023SJohn Marino or detection that the trailing '\0' doesn't need to be
1213e4b17023SJohn Marino written, if it will be immediately overwritten.
1214e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1215e4b17023SJohn Marino if (lhs)
1216e4b17023SJohn Marino {
1217e4b17023SJohn Marino dsi->endptr = lhs;
1218e4b17023SJohn Marino zsi = zero_length_string (lhs, dsi);
1219e4b17023SJohn Marino }
1220e4b17023SJohn Marino break;
1221e4b17023SJohn Marino default:
1222e4b17023SJohn Marino gcc_unreachable ();
1223e4b17023SJohn Marino }
1224e4b17023SJohn Marino if (zsi != NULL)
1225e4b17023SJohn Marino zsi->dont_invalidate = true;
1226e4b17023SJohn Marino
1227e4b17023SJohn Marino if (fn == NULL_TREE)
1228e4b17023SJohn Marino return;
1229e4b17023SJohn Marino
1230e4b17023SJohn Marino args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1231e4b17023SJohn Marino type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1232e4b17023SJohn Marino
1233e4b17023SJohn Marino len = fold_convert_loc (loc, type, unshare_expr (srclen));
1234e4b17023SJohn Marino len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1235e4b17023SJohn Marino len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1236e4b17023SJohn Marino GSI_SAME_STMT);
1237e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1238e4b17023SJohn Marino {
1239e4b17023SJohn Marino fprintf (dump_file, "Optimizing: ");
1240e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1241e4b17023SJohn Marino }
1242e4b17023SJohn Marino if (gimple_call_num_args (stmt) == 2)
1243e4b17023SJohn Marino success = update_gimple_call (gsi, fn, 3, dst, src, len);
1244e4b17023SJohn Marino else
1245e4b17023SJohn Marino success = update_gimple_call (gsi, fn, 4, dst, src, len,
1246e4b17023SJohn Marino gimple_call_arg (stmt, 2));
1247e4b17023SJohn Marino if (success)
1248e4b17023SJohn Marino {
1249e4b17023SJohn Marino stmt = gsi_stmt (*gsi);
1250e4b17023SJohn Marino update_stmt (stmt);
1251e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1252e4b17023SJohn Marino {
1253e4b17023SJohn Marino fprintf (dump_file, "into: ");
1254e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1255e4b17023SJohn Marino }
1256e4b17023SJohn Marino /* Allow adjust_last_stmt to decrease this memcpy's size. */
1257e4b17023SJohn Marino laststmt.stmt = stmt;
1258e4b17023SJohn Marino laststmt.len = srclen;
1259e4b17023SJohn Marino laststmt.stridx = dsi->idx;
1260e4b17023SJohn Marino }
1261e4b17023SJohn Marino else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1262e4b17023SJohn Marino fprintf (dump_file, "not possible.\n");
1263e4b17023SJohn Marino }
1264e4b17023SJohn Marino
1265e4b17023SJohn Marino /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1266e4b17023SJohn Marino If strlen of the second argument is known and length of the third argument
1267e4b17023SJohn Marino is that plus one, strlen of the first argument is the same after this
1268e4b17023SJohn Marino call. */
1269e4b17023SJohn Marino
1270e4b17023SJohn Marino static void
handle_builtin_memcpy(enum built_in_function bcode,gimple_stmt_iterator * gsi)1271e4b17023SJohn Marino handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1272e4b17023SJohn Marino {
1273e4b17023SJohn Marino int idx, didx;
1274e4b17023SJohn Marino tree src, dst, len, lhs, oldlen, newlen;
1275e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi);
1276e4b17023SJohn Marino strinfo si, dsi, olddsi;
1277e4b17023SJohn Marino
1278e4b17023SJohn Marino len = gimple_call_arg (stmt, 2);
1279e4b17023SJohn Marino src = gimple_call_arg (stmt, 1);
1280e4b17023SJohn Marino dst = gimple_call_arg (stmt, 0);
1281e4b17023SJohn Marino idx = get_stridx (src);
1282e4b17023SJohn Marino if (idx == 0)
1283e4b17023SJohn Marino return;
1284e4b17023SJohn Marino
1285e4b17023SJohn Marino didx = get_stridx (dst);
1286e4b17023SJohn Marino olddsi = NULL;
1287e4b17023SJohn Marino if (didx > 0)
1288e4b17023SJohn Marino olddsi = get_strinfo (didx);
1289e4b17023SJohn Marino else if (didx < 0)
1290e4b17023SJohn Marino return;
1291e4b17023SJohn Marino
1292e4b17023SJohn Marino if (olddsi != NULL
1293e4b17023SJohn Marino && host_integerp (len, 1)
1294e4b17023SJohn Marino && !integer_zerop (len))
1295e4b17023SJohn Marino adjust_last_stmt (olddsi, stmt, false);
1296e4b17023SJohn Marino
1297e4b17023SJohn Marino if (idx > 0)
1298e4b17023SJohn Marino {
1299e4b17023SJohn Marino gimple def_stmt;
1300e4b17023SJohn Marino
1301e4b17023SJohn Marino /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1302e4b17023SJohn Marino si = get_strinfo (idx);
1303e4b17023SJohn Marino if (si == NULL || si->length == NULL_TREE)
1304e4b17023SJohn Marino return;
1305e4b17023SJohn Marino if (TREE_CODE (len) != SSA_NAME)
1306e4b17023SJohn Marino return;
1307e4b17023SJohn Marino def_stmt = SSA_NAME_DEF_STMT (len);
1308e4b17023SJohn Marino if (!is_gimple_assign (def_stmt)
1309e4b17023SJohn Marino || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1310e4b17023SJohn Marino || gimple_assign_rhs1 (def_stmt) != si->length
1311e4b17023SJohn Marino || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1312e4b17023SJohn Marino return;
1313e4b17023SJohn Marino }
1314e4b17023SJohn Marino else
1315e4b17023SJohn Marino {
1316e4b17023SJohn Marino si = NULL;
1317e4b17023SJohn Marino /* Handle memcpy (x, "abcd", 5) or
1318e4b17023SJohn Marino memcpy (x, "abc\0uvw", 7). */
1319e4b17023SJohn Marino if (!host_integerp (len, 1)
1320e4b17023SJohn Marino || (unsigned HOST_WIDE_INT) tree_low_cst (len, 1)
1321e4b17023SJohn Marino <= (unsigned HOST_WIDE_INT) ~idx)
1322e4b17023SJohn Marino return;
1323e4b17023SJohn Marino }
1324e4b17023SJohn Marino
1325e4b17023SJohn Marino if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1326e4b17023SJohn Marino adjust_last_stmt (olddsi, stmt, false);
1327e4b17023SJohn Marino
1328e4b17023SJohn Marino if (didx == 0)
1329e4b17023SJohn Marino {
1330e4b17023SJohn Marino didx = new_stridx (dst);
1331e4b17023SJohn Marino if (didx == 0)
1332e4b17023SJohn Marino return;
1333e4b17023SJohn Marino }
1334e4b17023SJohn Marino if (si != NULL)
1335e4b17023SJohn Marino newlen = si->length;
1336e4b17023SJohn Marino else
1337e4b17023SJohn Marino newlen = build_int_cst (size_type_node, ~idx);
1338e4b17023SJohn Marino oldlen = NULL_TREE;
1339e4b17023SJohn Marino if (olddsi != NULL)
1340e4b17023SJohn Marino {
1341e4b17023SJohn Marino dsi = unshare_strinfo (olddsi);
1342e4b17023SJohn Marino oldlen = olddsi->length;
1343e4b17023SJohn Marino dsi->length = newlen;
1344e4b17023SJohn Marino /* Break the chain, so adjust_related_strinfo on later pointers in
1345e4b17023SJohn Marino the chain won't adjust this one anymore. */
1346e4b17023SJohn Marino dsi->next = 0;
1347e4b17023SJohn Marino dsi->stmt = NULL;
1348e4b17023SJohn Marino dsi->endptr = NULL_TREE;
1349e4b17023SJohn Marino }
1350e4b17023SJohn Marino else
1351e4b17023SJohn Marino {
1352e4b17023SJohn Marino dsi = new_strinfo (dst, didx, newlen);
1353e4b17023SJohn Marino set_strinfo (didx, dsi);
1354e4b17023SJohn Marino find_equal_ptrs (dst, didx);
1355e4b17023SJohn Marino }
1356e4b17023SJohn Marino dsi->writable = true;
1357e4b17023SJohn Marino dsi->dont_invalidate = true;
1358e4b17023SJohn Marino if (olddsi != NULL)
1359e4b17023SJohn Marino {
1360e4b17023SJohn Marino tree adj = NULL_TREE;
1361e4b17023SJohn Marino location_t loc = gimple_location (stmt);
1362e4b17023SJohn Marino if (oldlen == NULL_TREE)
1363e4b17023SJohn Marino ;
1364e4b17023SJohn Marino else if (integer_zerop (oldlen))
1365e4b17023SJohn Marino adj = dsi->length;
1366e4b17023SJohn Marino else if (TREE_CODE (oldlen) == INTEGER_CST
1367e4b17023SJohn Marino || TREE_CODE (dsi->length) == INTEGER_CST)
1368e4b17023SJohn Marino adj = fold_build2_loc (loc, MINUS_EXPR,
1369e4b17023SJohn Marino TREE_TYPE (dsi->length), dsi->length,
1370e4b17023SJohn Marino fold_convert_loc (loc, TREE_TYPE (dsi->length),
1371e4b17023SJohn Marino oldlen));
1372e4b17023SJohn Marino if (adj != NULL_TREE)
1373e4b17023SJohn Marino adjust_related_strinfos (loc, dsi, adj);
1374e4b17023SJohn Marino else
1375e4b17023SJohn Marino dsi->prev = 0;
1376e4b17023SJohn Marino }
1377e4b17023SJohn Marino /* memcpy src may not overlap dst, so src doesn't need to be
1378e4b17023SJohn Marino invalidated either. */
1379e4b17023SJohn Marino if (si != NULL)
1380e4b17023SJohn Marino si->dont_invalidate = true;
1381e4b17023SJohn Marino
1382e4b17023SJohn Marino lhs = gimple_call_lhs (stmt);
1383e4b17023SJohn Marino switch (bcode)
1384e4b17023SJohn Marino {
1385e4b17023SJohn Marino case BUILT_IN_MEMCPY:
1386e4b17023SJohn Marino case BUILT_IN_MEMCPY_CHK:
1387e4b17023SJohn Marino /* Allow adjust_last_stmt to decrease this memcpy's size. */
1388e4b17023SJohn Marino laststmt.stmt = stmt;
1389e4b17023SJohn Marino laststmt.len = dsi->length;
1390e4b17023SJohn Marino laststmt.stridx = dsi->idx;
1391e4b17023SJohn Marino if (lhs)
1392e4b17023SJohn Marino VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (lhs), didx);
1393e4b17023SJohn Marino break;
1394e4b17023SJohn Marino case BUILT_IN_MEMPCPY:
1395e4b17023SJohn Marino case BUILT_IN_MEMPCPY_CHK:
1396e4b17023SJohn Marino break;
1397e4b17023SJohn Marino default:
1398e4b17023SJohn Marino gcc_unreachable ();
1399e4b17023SJohn Marino }
1400e4b17023SJohn Marino }
1401e4b17023SJohn Marino
1402e4b17023SJohn Marino /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1403e4b17023SJohn Marino If strlen of the second argument is known, strlen of the first argument
1404e4b17023SJohn Marino is increased by the length of the second argument. Furthermore, attempt
1405e4b17023SJohn Marino to convert it to memcpy/strcpy if the length of the first argument
1406e4b17023SJohn Marino is known. */
1407e4b17023SJohn Marino
1408e4b17023SJohn Marino static void
handle_builtin_strcat(enum built_in_function bcode,gimple_stmt_iterator * gsi)1409e4b17023SJohn Marino handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1410e4b17023SJohn Marino {
1411e4b17023SJohn Marino int idx, didx;
1412e4b17023SJohn Marino tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1413e4b17023SJohn Marino bool success;
1414e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi);
1415e4b17023SJohn Marino strinfo si, dsi;
1416e4b17023SJohn Marino location_t loc;
1417e4b17023SJohn Marino
1418e4b17023SJohn Marino src = gimple_call_arg (stmt, 1);
1419e4b17023SJohn Marino dst = gimple_call_arg (stmt, 0);
1420e4b17023SJohn Marino lhs = gimple_call_lhs (stmt);
1421e4b17023SJohn Marino
1422e4b17023SJohn Marino didx = get_stridx (dst);
1423e4b17023SJohn Marino if (didx < 0)
1424e4b17023SJohn Marino return;
1425e4b17023SJohn Marino
1426e4b17023SJohn Marino dsi = NULL;
1427e4b17023SJohn Marino if (didx > 0)
1428e4b17023SJohn Marino dsi = get_strinfo (didx);
1429e4b17023SJohn Marino if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1430e4b17023SJohn Marino {
1431e4b17023SJohn Marino /* strcat (p, q) can be transformed into
1432e4b17023SJohn Marino tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1433e4b17023SJohn Marino with length endptr - p if we need to compute the length
1434e4b17023SJohn Marino later on. Don't do this transformation if we don't need
1435e4b17023SJohn Marino it. */
1436e4b17023SJohn Marino if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1437e4b17023SJohn Marino {
1438e4b17023SJohn Marino if (didx == 0)
1439e4b17023SJohn Marino {
1440e4b17023SJohn Marino didx = new_stridx (dst);
1441e4b17023SJohn Marino if (didx == 0)
1442e4b17023SJohn Marino return;
1443e4b17023SJohn Marino }
1444e4b17023SJohn Marino if (dsi == NULL)
1445e4b17023SJohn Marino {
1446e4b17023SJohn Marino dsi = new_strinfo (dst, didx, NULL_TREE);
1447e4b17023SJohn Marino set_strinfo (didx, dsi);
1448e4b17023SJohn Marino find_equal_ptrs (dst, didx);
1449e4b17023SJohn Marino }
1450e4b17023SJohn Marino else
1451e4b17023SJohn Marino {
1452e4b17023SJohn Marino dsi = unshare_strinfo (dsi);
1453e4b17023SJohn Marino dsi->length = NULL_TREE;
1454e4b17023SJohn Marino dsi->next = 0;
1455e4b17023SJohn Marino dsi->endptr = NULL_TREE;
1456e4b17023SJohn Marino }
1457e4b17023SJohn Marino dsi->writable = true;
1458e4b17023SJohn Marino dsi->stmt = stmt;
1459e4b17023SJohn Marino dsi->dont_invalidate = true;
1460e4b17023SJohn Marino }
1461e4b17023SJohn Marino return;
1462e4b17023SJohn Marino }
1463e4b17023SJohn Marino
1464e4b17023SJohn Marino srclen = NULL_TREE;
1465e4b17023SJohn Marino si = NULL;
1466e4b17023SJohn Marino idx = get_stridx (src);
1467e4b17023SJohn Marino if (idx < 0)
1468e4b17023SJohn Marino srclen = build_int_cst (size_type_node, ~idx);
1469e4b17023SJohn Marino else if (idx > 0)
1470e4b17023SJohn Marino {
1471e4b17023SJohn Marino si = get_strinfo (idx);
1472e4b17023SJohn Marino if (si != NULL)
1473e4b17023SJohn Marino srclen = get_string_length (si);
1474e4b17023SJohn Marino }
1475e4b17023SJohn Marino
1476e4b17023SJohn Marino loc = gimple_location (stmt);
1477e4b17023SJohn Marino dstlen = dsi->length;
1478e4b17023SJohn Marino endptr = dsi->endptr;
1479e4b17023SJohn Marino
1480e4b17023SJohn Marino dsi = unshare_strinfo (dsi);
1481e4b17023SJohn Marino dsi->endptr = NULL_TREE;
1482e4b17023SJohn Marino dsi->stmt = NULL;
1483e4b17023SJohn Marino dsi->writable = true;
1484e4b17023SJohn Marino
1485e4b17023SJohn Marino if (srclen != NULL_TREE)
1486e4b17023SJohn Marino {
1487e4b17023SJohn Marino dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1488e4b17023SJohn Marino dsi->length, srclen);
1489e4b17023SJohn Marino adjust_related_strinfos (loc, dsi, srclen);
1490e4b17023SJohn Marino dsi->dont_invalidate = true;
1491e4b17023SJohn Marino }
1492e4b17023SJohn Marino else
1493e4b17023SJohn Marino {
1494e4b17023SJohn Marino dsi->length = NULL;
1495e4b17023SJohn Marino if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1496e4b17023SJohn Marino dsi->dont_invalidate = true;
1497e4b17023SJohn Marino }
1498e4b17023SJohn Marino
1499e4b17023SJohn Marino if (si != NULL)
1500e4b17023SJohn Marino /* strcat src may not overlap dst, so src doesn't need to be
1501e4b17023SJohn Marino invalidated either. */
1502e4b17023SJohn Marino si->dont_invalidate = true;
1503e4b17023SJohn Marino
1504e4b17023SJohn Marino /* For now. Could remove the lhs from the call and add
1505e4b17023SJohn Marino lhs = dst; afterwards. */
1506e4b17023SJohn Marino if (lhs)
1507e4b17023SJohn Marino return;
1508e4b17023SJohn Marino
1509e4b17023SJohn Marino fn = NULL_TREE;
1510e4b17023SJohn Marino objsz = NULL_TREE;
1511e4b17023SJohn Marino switch (bcode)
1512e4b17023SJohn Marino {
1513e4b17023SJohn Marino case BUILT_IN_STRCAT:
1514e4b17023SJohn Marino if (srclen != NULL_TREE)
1515e4b17023SJohn Marino fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1516e4b17023SJohn Marino else
1517e4b17023SJohn Marino fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1518e4b17023SJohn Marino break;
1519e4b17023SJohn Marino case BUILT_IN_STRCAT_CHK:
1520e4b17023SJohn Marino if (srclen != NULL_TREE)
1521e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1522e4b17023SJohn Marino else
1523e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1524e4b17023SJohn Marino objsz = gimple_call_arg (stmt, 2);
1525e4b17023SJohn Marino break;
1526e4b17023SJohn Marino default:
1527e4b17023SJohn Marino gcc_unreachable ();
1528e4b17023SJohn Marino }
1529e4b17023SJohn Marino
1530e4b17023SJohn Marino if (fn == NULL_TREE)
1531e4b17023SJohn Marino return;
1532e4b17023SJohn Marino
1533e4b17023SJohn Marino len = NULL_TREE;
1534e4b17023SJohn Marino if (srclen != NULL_TREE)
1535e4b17023SJohn Marino {
1536e4b17023SJohn Marino args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1537e4b17023SJohn Marino type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1538e4b17023SJohn Marino
1539e4b17023SJohn Marino len = fold_convert_loc (loc, type, unshare_expr (srclen));
1540e4b17023SJohn Marino len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1541e4b17023SJohn Marino build_int_cst (type, 1));
1542e4b17023SJohn Marino len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1543e4b17023SJohn Marino GSI_SAME_STMT);
1544e4b17023SJohn Marino }
1545e4b17023SJohn Marino if (endptr)
1546e4b17023SJohn Marino dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1547e4b17023SJohn Marino else
1548e4b17023SJohn Marino dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1549e4b17023SJohn Marino TREE_TYPE (dst), unshare_expr (dst),
1550e4b17023SJohn Marino fold_convert_loc (loc, sizetype,
1551e4b17023SJohn Marino unshare_expr (dstlen)));
1552e4b17023SJohn Marino dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1553e4b17023SJohn Marino GSI_SAME_STMT);
1554e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1555e4b17023SJohn Marino {
1556e4b17023SJohn Marino fprintf (dump_file, "Optimizing: ");
1557e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1558e4b17023SJohn Marino }
1559e4b17023SJohn Marino if (srclen != NULL_TREE)
1560e4b17023SJohn Marino success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1561e4b17023SJohn Marino dst, src, len, objsz);
1562e4b17023SJohn Marino else
1563e4b17023SJohn Marino success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1564e4b17023SJohn Marino dst, src, objsz);
1565e4b17023SJohn Marino if (success)
1566e4b17023SJohn Marino {
1567e4b17023SJohn Marino stmt = gsi_stmt (*gsi);
1568e4b17023SJohn Marino update_stmt (stmt);
1569e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1570e4b17023SJohn Marino {
1571e4b17023SJohn Marino fprintf (dump_file, "into: ");
1572e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1573e4b17023SJohn Marino }
1574e4b17023SJohn Marino /* If srclen == NULL, note that current string length can be
1575e4b17023SJohn Marino computed by transforming this strcpy into stpcpy. */
1576e4b17023SJohn Marino if (srclen == NULL_TREE && dsi->dont_invalidate)
1577e4b17023SJohn Marino dsi->stmt = stmt;
1578e4b17023SJohn Marino adjust_last_stmt (dsi, stmt, true);
1579e4b17023SJohn Marino if (srclen != NULL_TREE)
1580e4b17023SJohn Marino {
1581e4b17023SJohn Marino laststmt.stmt = stmt;
1582e4b17023SJohn Marino laststmt.len = srclen;
1583e4b17023SJohn Marino laststmt.stridx = dsi->idx;
1584e4b17023SJohn Marino }
1585e4b17023SJohn Marino }
1586e4b17023SJohn Marino else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1587e4b17023SJohn Marino fprintf (dump_file, "not possible.\n");
1588e4b17023SJohn Marino }
1589e4b17023SJohn Marino
1590e4b17023SJohn Marino /* Handle a POINTER_PLUS_EXPR statement.
1591e4b17023SJohn Marino For p = "abcd" + 2; compute associated length, or if
1592e4b17023SJohn Marino p = q + off is pointing to a '\0' character of a string, call
1593e4b17023SJohn Marino zero_length_string on it. */
1594e4b17023SJohn Marino
1595e4b17023SJohn Marino static void
handle_pointer_plus(gimple_stmt_iterator * gsi)1596e4b17023SJohn Marino handle_pointer_plus (gimple_stmt_iterator *gsi)
1597e4b17023SJohn Marino {
1598e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi);
1599e4b17023SJohn Marino tree lhs = gimple_assign_lhs (stmt), off;
1600e4b17023SJohn Marino int idx = get_stridx (gimple_assign_rhs1 (stmt));
1601e4b17023SJohn Marino strinfo si, zsi;
1602e4b17023SJohn Marino
1603e4b17023SJohn Marino if (idx == 0)
1604e4b17023SJohn Marino return;
1605e4b17023SJohn Marino
1606e4b17023SJohn Marino if (idx < 0)
1607e4b17023SJohn Marino {
1608e4b17023SJohn Marino tree off = gimple_assign_rhs2 (stmt);
1609e4b17023SJohn Marino if (host_integerp (off, 1)
1610e4b17023SJohn Marino && (unsigned HOST_WIDE_INT) tree_low_cst (off, 1)
1611e4b17023SJohn Marino <= (unsigned HOST_WIDE_INT) ~idx)
1612e4b17023SJohn Marino VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (lhs),
1613e4b17023SJohn Marino ~(~idx - (int) tree_low_cst (off, 1)));
1614e4b17023SJohn Marino return;
1615e4b17023SJohn Marino }
1616e4b17023SJohn Marino
1617e4b17023SJohn Marino si = get_strinfo (idx);
1618e4b17023SJohn Marino if (si == NULL || si->length == NULL_TREE)
1619e4b17023SJohn Marino return;
1620e4b17023SJohn Marino
1621e4b17023SJohn Marino off = gimple_assign_rhs2 (stmt);
1622e4b17023SJohn Marino zsi = NULL;
1623e4b17023SJohn Marino if (operand_equal_p (si->length, off, 0))
1624e4b17023SJohn Marino zsi = zero_length_string (lhs, si);
1625e4b17023SJohn Marino else if (TREE_CODE (off) == SSA_NAME)
1626e4b17023SJohn Marino {
1627e4b17023SJohn Marino gimple def_stmt = SSA_NAME_DEF_STMT (off);
1628e4b17023SJohn Marino if (gimple_assign_single_p (def_stmt)
1629e4b17023SJohn Marino && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
1630e4b17023SJohn Marino zsi = zero_length_string (lhs, si);
1631e4b17023SJohn Marino }
1632e4b17023SJohn Marino if (zsi != NULL
1633e4b17023SJohn Marino && si->endptr != NULL_TREE
1634e4b17023SJohn Marino && si->endptr != lhs
1635e4b17023SJohn Marino && TREE_CODE (si->endptr) == SSA_NAME)
1636e4b17023SJohn Marino {
1637e4b17023SJohn Marino enum tree_code rhs_code
1638e4b17023SJohn Marino = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
1639e4b17023SJohn Marino ? SSA_NAME : NOP_EXPR;
1640e4b17023SJohn Marino gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr, NULL_TREE);
1641e4b17023SJohn Marino gcc_assert (gsi_stmt (*gsi) == stmt);
1642e4b17023SJohn Marino update_stmt (stmt);
1643e4b17023SJohn Marino }
1644e4b17023SJohn Marino }
1645e4b17023SJohn Marino
1646e4b17023SJohn Marino /* Handle a single character store. */
1647e4b17023SJohn Marino
1648e4b17023SJohn Marino static bool
handle_char_store(gimple_stmt_iterator * gsi)1649e4b17023SJohn Marino handle_char_store (gimple_stmt_iterator *gsi)
1650e4b17023SJohn Marino {
1651e4b17023SJohn Marino int idx = -1;
1652e4b17023SJohn Marino strinfo si = NULL;
1653e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi);
1654e4b17023SJohn Marino tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
1655e4b17023SJohn Marino
1656e4b17023SJohn Marino if (TREE_CODE (lhs) == MEM_REF
1657e4b17023SJohn Marino && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
1658e4b17023SJohn Marino {
1659e4b17023SJohn Marino if (integer_zerop (TREE_OPERAND (lhs, 1)))
1660e4b17023SJohn Marino {
1661e4b17023SJohn Marino ssaname = TREE_OPERAND (lhs, 0);
1662e4b17023SJohn Marino idx = get_stridx (ssaname);
1663e4b17023SJohn Marino }
1664e4b17023SJohn Marino }
1665e4b17023SJohn Marino else
1666e4b17023SJohn Marino idx = get_addr_stridx (lhs);
1667e4b17023SJohn Marino
1668e4b17023SJohn Marino if (idx > 0)
1669e4b17023SJohn Marino {
1670e4b17023SJohn Marino si = get_strinfo (idx);
1671e4b17023SJohn Marino if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
1672e4b17023SJohn Marino {
1673e4b17023SJohn Marino if (initializer_zerop (gimple_assign_rhs1 (stmt)))
1674e4b17023SJohn Marino {
1675e4b17023SJohn Marino /* When storing '\0', the store can be removed
1676e4b17023SJohn Marino if we know it has been stored in the current function. */
1677e4b17023SJohn Marino if (!stmt_could_throw_p (stmt) && si->writable)
1678e4b17023SJohn Marino {
1679e4b17023SJohn Marino unlink_stmt_vdef (stmt);
1680e4b17023SJohn Marino release_defs (stmt);
1681e4b17023SJohn Marino gsi_remove (gsi, true);
1682e4b17023SJohn Marino return false;
1683e4b17023SJohn Marino }
1684e4b17023SJohn Marino else
1685e4b17023SJohn Marino {
1686e4b17023SJohn Marino si->writable = true;
1687e4b17023SJohn Marino si->dont_invalidate = true;
1688e4b17023SJohn Marino }
1689e4b17023SJohn Marino }
1690e4b17023SJohn Marino else
1691e4b17023SJohn Marino /* Otherwise this statement overwrites the '\0' with
1692e4b17023SJohn Marino something, if the previous stmt was a memcpy,
1693e4b17023SJohn Marino its length may be decreased. */
1694e4b17023SJohn Marino adjust_last_stmt (si, stmt, false);
1695e4b17023SJohn Marino }
1696*95d28233SJohn Marino else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt)))
1697e4b17023SJohn Marino {
1698e4b17023SJohn Marino si = unshare_strinfo (si);
1699e4b17023SJohn Marino si->length = build_int_cst (size_type_node, 0);
1700e4b17023SJohn Marino si->endptr = NULL;
1701e4b17023SJohn Marino si->prev = 0;
1702e4b17023SJohn Marino si->next = 0;
1703e4b17023SJohn Marino si->stmt = NULL;
1704e4b17023SJohn Marino si->first = 0;
1705e4b17023SJohn Marino si->writable = true;
1706e4b17023SJohn Marino if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
1707e4b17023SJohn Marino si->endptr = ssaname;
1708e4b17023SJohn Marino si->dont_invalidate = true;
1709e4b17023SJohn Marino }
1710e4b17023SJohn Marino }
1711e4b17023SJohn Marino else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
1712e4b17023SJohn Marino {
1713e4b17023SJohn Marino if (ssaname)
1714e4b17023SJohn Marino {
1715e4b17023SJohn Marino si = zero_length_string (ssaname, NULL);
1716e4b17023SJohn Marino if (si != NULL)
1717e4b17023SJohn Marino si->dont_invalidate = true;
1718e4b17023SJohn Marino }
1719e4b17023SJohn Marino else
1720e4b17023SJohn Marino {
1721e4b17023SJohn Marino int idx = new_addr_stridx (lhs);
1722e4b17023SJohn Marino if (idx != 0)
1723e4b17023SJohn Marino {
1724e4b17023SJohn Marino si = new_strinfo (build_fold_addr_expr (lhs), idx,
1725e4b17023SJohn Marino build_int_cst (size_type_node, 0));
1726e4b17023SJohn Marino set_strinfo (idx, si);
1727e4b17023SJohn Marino si->dont_invalidate = true;
1728e4b17023SJohn Marino }
1729e4b17023SJohn Marino }
1730e4b17023SJohn Marino if (si != NULL)
1731e4b17023SJohn Marino si->writable = true;
1732e4b17023SJohn Marino }
1733e4b17023SJohn Marino
1734e4b17023SJohn Marino if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
1735e4b17023SJohn Marino {
1736e4b17023SJohn Marino /* Allow adjust_last_stmt to remove it if the stored '\0'
1737e4b17023SJohn Marino is immediately overwritten. */
1738e4b17023SJohn Marino laststmt.stmt = stmt;
1739e4b17023SJohn Marino laststmt.len = build_int_cst (size_type_node, 1);
1740e4b17023SJohn Marino laststmt.stridx = si->idx;
1741e4b17023SJohn Marino }
1742e4b17023SJohn Marino return true;
1743e4b17023SJohn Marino }
1744e4b17023SJohn Marino
1745e4b17023SJohn Marino /* Attempt to optimize a single statement at *GSI using string length
1746e4b17023SJohn Marino knowledge. */
1747e4b17023SJohn Marino
1748e4b17023SJohn Marino static bool
strlen_optimize_stmt(gimple_stmt_iterator * gsi)1749e4b17023SJohn Marino strlen_optimize_stmt (gimple_stmt_iterator *gsi)
1750e4b17023SJohn Marino {
1751e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi);
1752e4b17023SJohn Marino
1753e4b17023SJohn Marino if (is_gimple_call (stmt))
1754e4b17023SJohn Marino {
1755e4b17023SJohn Marino tree callee = gimple_call_fndecl (stmt);
17565ce9237cSJohn Marino if (gimple_call_builtin_class_p (stmt, BUILT_IN_NORMAL))
1757e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (callee))
1758e4b17023SJohn Marino {
1759e4b17023SJohn Marino case BUILT_IN_STRLEN:
1760e4b17023SJohn Marino handle_builtin_strlen (gsi);
1761e4b17023SJohn Marino break;
1762e4b17023SJohn Marino case BUILT_IN_STRCHR:
1763e4b17023SJohn Marino handle_builtin_strchr (gsi);
1764e4b17023SJohn Marino break;
1765e4b17023SJohn Marino case BUILT_IN_STRCPY:
1766e4b17023SJohn Marino case BUILT_IN_STRCPY_CHK:
1767e4b17023SJohn Marino case BUILT_IN_STPCPY:
1768e4b17023SJohn Marino case BUILT_IN_STPCPY_CHK:
1769e4b17023SJohn Marino handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
1770e4b17023SJohn Marino break;
1771e4b17023SJohn Marino case BUILT_IN_MEMCPY:
1772e4b17023SJohn Marino case BUILT_IN_MEMCPY_CHK:
1773e4b17023SJohn Marino case BUILT_IN_MEMPCPY:
1774e4b17023SJohn Marino case BUILT_IN_MEMPCPY_CHK:
1775e4b17023SJohn Marino handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
1776e4b17023SJohn Marino break;
1777e4b17023SJohn Marino case BUILT_IN_STRCAT:
1778e4b17023SJohn Marino case BUILT_IN_STRCAT_CHK:
1779e4b17023SJohn Marino handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
1780e4b17023SJohn Marino break;
1781e4b17023SJohn Marino default:
1782e4b17023SJohn Marino break;
1783e4b17023SJohn Marino }
1784e4b17023SJohn Marino }
1785e4b17023SJohn Marino else if (is_gimple_assign (stmt))
1786e4b17023SJohn Marino {
1787e4b17023SJohn Marino tree lhs = gimple_assign_lhs (stmt);
1788e4b17023SJohn Marino
1789e4b17023SJohn Marino if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
1790e4b17023SJohn Marino {
1791e4b17023SJohn Marino if (gimple_assign_single_p (stmt)
1792e4b17023SJohn Marino || (gimple_assign_cast_p (stmt)
1793e4b17023SJohn Marino && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
1794e4b17023SJohn Marino {
1795e4b17023SJohn Marino int idx = get_stridx (gimple_assign_rhs1 (stmt));
1796e4b17023SJohn Marino VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (lhs),
1797e4b17023SJohn Marino idx);
1798e4b17023SJohn Marino }
1799e4b17023SJohn Marino else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
1800e4b17023SJohn Marino handle_pointer_plus (gsi);
1801e4b17023SJohn Marino }
1802e4b17023SJohn Marino else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
1803e4b17023SJohn Marino {
1804e4b17023SJohn Marino tree type = TREE_TYPE (lhs);
1805e4b17023SJohn Marino if (TREE_CODE (type) == ARRAY_TYPE)
1806e4b17023SJohn Marino type = TREE_TYPE (type);
1807e4b17023SJohn Marino if (TREE_CODE (type) == INTEGER_TYPE
1808e4b17023SJohn Marino && TYPE_MODE (type) == TYPE_MODE (char_type_node)
1809e4b17023SJohn Marino && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
1810e4b17023SJohn Marino {
1811e4b17023SJohn Marino if (! handle_char_store (gsi))
1812e4b17023SJohn Marino return false;
1813e4b17023SJohn Marino }
1814e4b17023SJohn Marino }
1815e4b17023SJohn Marino }
1816e4b17023SJohn Marino
1817e4b17023SJohn Marino if (gimple_vdef (stmt))
1818e4b17023SJohn Marino maybe_invalidate (stmt);
1819e4b17023SJohn Marino return true;
1820e4b17023SJohn Marino }
1821e4b17023SJohn Marino
1822e4b17023SJohn Marino /* Recursively call maybe_invalidate on stmts that might be executed
1823e4b17023SJohn Marino in between dombb and current bb and that contain a vdef. Stop when
1824e4b17023SJohn Marino *count stmts are inspected, or if the whole strinfo vector has
1825e4b17023SJohn Marino been invalidated. */
1826e4b17023SJohn Marino
1827e4b17023SJohn Marino static void
do_invalidate(basic_block dombb,gimple phi,bitmap visited,int * count)1828e4b17023SJohn Marino do_invalidate (basic_block dombb, gimple phi, bitmap visited, int *count)
1829e4b17023SJohn Marino {
1830e4b17023SJohn Marino unsigned int i, n = gimple_phi_num_args (phi);
1831e4b17023SJohn Marino
1832e4b17023SJohn Marino for (i = 0; i < n; i++)
1833e4b17023SJohn Marino {
1834e4b17023SJohn Marino tree vuse = gimple_phi_arg_def (phi, i);
1835e4b17023SJohn Marino gimple stmt = SSA_NAME_DEF_STMT (vuse);
1836e4b17023SJohn Marino basic_block bb = gimple_bb (stmt);
1837e4b17023SJohn Marino if (bb == NULL
1838e4b17023SJohn Marino || bb == dombb
1839e4b17023SJohn Marino || !bitmap_set_bit (visited, bb->index)
1840e4b17023SJohn Marino || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
1841e4b17023SJohn Marino continue;
1842e4b17023SJohn Marino while (1)
1843e4b17023SJohn Marino {
1844e4b17023SJohn Marino if (gimple_code (stmt) == GIMPLE_PHI)
1845e4b17023SJohn Marino {
1846e4b17023SJohn Marino do_invalidate (dombb, stmt, visited, count);
1847e4b17023SJohn Marino if (*count == 0)
1848e4b17023SJohn Marino return;
1849e4b17023SJohn Marino break;
1850e4b17023SJohn Marino }
1851e4b17023SJohn Marino if (--*count == 0)
1852e4b17023SJohn Marino return;
1853e4b17023SJohn Marino if (!maybe_invalidate (stmt))
1854e4b17023SJohn Marino {
1855e4b17023SJohn Marino *count = 0;
1856e4b17023SJohn Marino return;
1857e4b17023SJohn Marino }
1858e4b17023SJohn Marino vuse = gimple_vuse (stmt);
1859e4b17023SJohn Marino stmt = SSA_NAME_DEF_STMT (vuse);
1860e4b17023SJohn Marino if (gimple_bb (stmt) != bb)
1861e4b17023SJohn Marino {
1862e4b17023SJohn Marino bb = gimple_bb (stmt);
1863e4b17023SJohn Marino if (bb == NULL
1864e4b17023SJohn Marino || bb == dombb
1865e4b17023SJohn Marino || !bitmap_set_bit (visited, bb->index)
1866e4b17023SJohn Marino || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
1867e4b17023SJohn Marino break;
1868e4b17023SJohn Marino }
1869e4b17023SJohn Marino }
1870e4b17023SJohn Marino }
1871e4b17023SJohn Marino }
1872e4b17023SJohn Marino
1873e4b17023SJohn Marino /* Callback for walk_dominator_tree. Attempt to optimize various
1874e4b17023SJohn Marino string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
1875e4b17023SJohn Marino
1876e4b17023SJohn Marino static void
strlen_enter_block(struct dom_walk_data * walk_data ATTRIBUTE_UNUSED,basic_block bb)1877e4b17023SJohn Marino strlen_enter_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
1878e4b17023SJohn Marino basic_block bb)
1879e4b17023SJohn Marino {
1880e4b17023SJohn Marino gimple_stmt_iterator gsi;
1881e4b17023SJohn Marino basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
1882e4b17023SJohn Marino
1883e4b17023SJohn Marino if (dombb == NULL)
1884e4b17023SJohn Marino stridx_to_strinfo = NULL;
1885e4b17023SJohn Marino else
1886e4b17023SJohn Marino {
1887e4b17023SJohn Marino stridx_to_strinfo = (VEC(strinfo, heap) *) dombb->aux;
1888e4b17023SJohn Marino if (stridx_to_strinfo)
1889e4b17023SJohn Marino {
1890e4b17023SJohn Marino for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1891e4b17023SJohn Marino {
1892e4b17023SJohn Marino gimple phi = gsi_stmt (gsi);
1893e4b17023SJohn Marino if (!is_gimple_reg (gimple_phi_result (phi)))
1894e4b17023SJohn Marino {
1895e4b17023SJohn Marino bitmap visited = BITMAP_ALLOC (NULL);
1896e4b17023SJohn Marino int count_vdef = 100;
1897e4b17023SJohn Marino do_invalidate (dombb, phi, visited, &count_vdef);
1898e4b17023SJohn Marino BITMAP_FREE (visited);
1899*95d28233SJohn Marino if (count_vdef == 0)
1900*95d28233SJohn Marino {
1901*95d28233SJohn Marino /* If there were too many vdefs in between immediate
1902*95d28233SJohn Marino dominator and current bb, invalidate everything.
1903*95d28233SJohn Marino If stridx_to_strinfo has been unshared, we need
1904*95d28233SJohn Marino to free it, otherwise just set it to NULL. */
1905*95d28233SJohn Marino if (!strinfo_shared ())
1906*95d28233SJohn Marino {
1907*95d28233SJohn Marino unsigned int i;
1908*95d28233SJohn Marino strinfo si;
1909*95d28233SJohn Marino
1910*95d28233SJohn Marino for (i = 1;
1911*95d28233SJohn Marino VEC_iterate (strinfo, stridx_to_strinfo, i, si);
1912*95d28233SJohn Marino ++i)
1913*95d28233SJohn Marino {
1914*95d28233SJohn Marino free_strinfo (si);
1915*95d28233SJohn Marino VEC_replace (strinfo, stridx_to_strinfo,
1916*95d28233SJohn Marino i, NULL);
1917*95d28233SJohn Marino }
1918*95d28233SJohn Marino }
1919*95d28233SJohn Marino else
1920*95d28233SJohn Marino stridx_to_strinfo = NULL;
1921*95d28233SJohn Marino }
1922e4b17023SJohn Marino break;
1923e4b17023SJohn Marino }
1924e4b17023SJohn Marino }
1925e4b17023SJohn Marino }
1926e4b17023SJohn Marino }
1927e4b17023SJohn Marino
1928e4b17023SJohn Marino /* If all PHI arguments have the same string index, the PHI result
1929e4b17023SJohn Marino has it as well. */
1930e4b17023SJohn Marino for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1931e4b17023SJohn Marino {
1932e4b17023SJohn Marino gimple phi = gsi_stmt (gsi);
1933e4b17023SJohn Marino tree result = gimple_phi_result (phi);
1934e4b17023SJohn Marino if (is_gimple_reg (result) && POINTER_TYPE_P (TREE_TYPE (result)))
1935e4b17023SJohn Marino {
1936e4b17023SJohn Marino int idx = get_stridx (gimple_phi_arg_def (phi, 0));
1937e4b17023SJohn Marino if (idx != 0)
1938e4b17023SJohn Marino {
1939e4b17023SJohn Marino unsigned int i, n = gimple_phi_num_args (phi);
1940e4b17023SJohn Marino for (i = 1; i < n; i++)
1941e4b17023SJohn Marino if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
1942e4b17023SJohn Marino break;
1943e4b17023SJohn Marino if (i == n)
1944e4b17023SJohn Marino VEC_replace (int, ssa_ver_to_stridx,
1945e4b17023SJohn Marino SSA_NAME_VERSION (result), idx);
1946e4b17023SJohn Marino }
1947e4b17023SJohn Marino }
1948e4b17023SJohn Marino }
1949e4b17023SJohn Marino
1950e4b17023SJohn Marino /* Attempt to optimize individual statements. */
1951e4b17023SJohn Marino for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
1952e4b17023SJohn Marino if (strlen_optimize_stmt (&gsi))
1953e4b17023SJohn Marino gsi_next (&gsi);
1954e4b17023SJohn Marino
1955e4b17023SJohn Marino bb->aux = stridx_to_strinfo;
1956e4b17023SJohn Marino if (VEC_length (strinfo, stridx_to_strinfo) && !strinfo_shared ())
1957e4b17023SJohn Marino VEC_replace (strinfo, stridx_to_strinfo, 0, (strinfo) bb);
1958e4b17023SJohn Marino }
1959e4b17023SJohn Marino
1960e4b17023SJohn Marino /* Callback for walk_dominator_tree. Free strinfo vector if it is
1961e4b17023SJohn Marino owned by the current bb, clear bb->aux. */
1962e4b17023SJohn Marino
1963e4b17023SJohn Marino static void
strlen_leave_block(struct dom_walk_data * walk_data ATTRIBUTE_UNUSED,basic_block bb)1964e4b17023SJohn Marino strlen_leave_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
1965e4b17023SJohn Marino basic_block bb)
1966e4b17023SJohn Marino {
1967e4b17023SJohn Marino if (bb->aux)
1968e4b17023SJohn Marino {
1969e4b17023SJohn Marino stridx_to_strinfo = (VEC(strinfo, heap) *) bb->aux;
1970e4b17023SJohn Marino if (VEC_length (strinfo, stridx_to_strinfo)
1971e4b17023SJohn Marino && VEC_index (strinfo, stridx_to_strinfo, 0) == (strinfo) bb)
1972e4b17023SJohn Marino {
1973e4b17023SJohn Marino unsigned int i;
1974e4b17023SJohn Marino strinfo si;
1975e4b17023SJohn Marino
1976e4b17023SJohn Marino for (i = 1; VEC_iterate (strinfo, stridx_to_strinfo, i, si); ++i)
1977e4b17023SJohn Marino free_strinfo (si);
1978e4b17023SJohn Marino VEC_free (strinfo, heap, stridx_to_strinfo);
1979e4b17023SJohn Marino }
1980e4b17023SJohn Marino bb->aux = NULL;
1981e4b17023SJohn Marino }
1982e4b17023SJohn Marino }
1983e4b17023SJohn Marino
1984e4b17023SJohn Marino /* Main entry point. */
1985e4b17023SJohn Marino
1986e4b17023SJohn Marino static unsigned int
tree_ssa_strlen(void)1987e4b17023SJohn Marino tree_ssa_strlen (void)
1988e4b17023SJohn Marino {
1989e4b17023SJohn Marino struct dom_walk_data walk_data;
1990e4b17023SJohn Marino
1991e4b17023SJohn Marino VEC_safe_grow_cleared (int, heap, ssa_ver_to_stridx, num_ssa_names);
1992e4b17023SJohn Marino max_stridx = 1;
1993e4b17023SJohn Marino strinfo_pool = create_alloc_pool ("strinfo_struct pool",
1994e4b17023SJohn Marino sizeof (struct strinfo_struct), 64);
1995e4b17023SJohn Marino
1996e4b17023SJohn Marino calculate_dominance_info (CDI_DOMINATORS);
1997e4b17023SJohn Marino
1998e4b17023SJohn Marino /* String length optimization is implemented as a walk of the dominator
1999e4b17023SJohn Marino tree and a forward walk of statements within each block. */
2000e4b17023SJohn Marino walk_data.dom_direction = CDI_DOMINATORS;
2001e4b17023SJohn Marino walk_data.initialize_block_local_data = NULL;
2002e4b17023SJohn Marino walk_data.before_dom_children = strlen_enter_block;
2003e4b17023SJohn Marino walk_data.after_dom_children = strlen_leave_block;
2004e4b17023SJohn Marino walk_data.block_local_data_size = 0;
2005e4b17023SJohn Marino walk_data.global_data = NULL;
2006e4b17023SJohn Marino
2007e4b17023SJohn Marino /* Initialize the dominator walker. */
2008e4b17023SJohn Marino init_walk_dominator_tree (&walk_data);
2009e4b17023SJohn Marino
2010e4b17023SJohn Marino /* Recursively walk the dominator tree. */
2011e4b17023SJohn Marino walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
2012e4b17023SJohn Marino
2013e4b17023SJohn Marino /* Finalize the dominator walker. */
2014e4b17023SJohn Marino fini_walk_dominator_tree (&walk_data);
2015e4b17023SJohn Marino
2016e4b17023SJohn Marino VEC_free (int, heap, ssa_ver_to_stridx);
2017e4b17023SJohn Marino free_alloc_pool (strinfo_pool);
2018e4b17023SJohn Marino if (decl_to_stridxlist_htab)
2019e4b17023SJohn Marino {
2020e4b17023SJohn Marino obstack_free (&stridx_obstack, NULL);
2021e4b17023SJohn Marino htab_delete (decl_to_stridxlist_htab);
2022e4b17023SJohn Marino decl_to_stridxlist_htab = NULL;
2023e4b17023SJohn Marino }
2024e4b17023SJohn Marino laststmt.stmt = NULL;
2025e4b17023SJohn Marino laststmt.len = NULL_TREE;
2026e4b17023SJohn Marino laststmt.stridx = 0;
2027e4b17023SJohn Marino
2028e4b17023SJohn Marino return 0;
2029e4b17023SJohn Marino }
2030e4b17023SJohn Marino
2031e4b17023SJohn Marino static bool
gate_strlen(void)2032e4b17023SJohn Marino gate_strlen (void)
2033e4b17023SJohn Marino {
2034e4b17023SJohn Marino return flag_optimize_strlen != 0;
2035e4b17023SJohn Marino }
2036e4b17023SJohn Marino
2037e4b17023SJohn Marino struct gimple_opt_pass pass_strlen =
2038e4b17023SJohn Marino {
2039e4b17023SJohn Marino {
2040e4b17023SJohn Marino GIMPLE_PASS,
2041e4b17023SJohn Marino "strlen", /* name */
2042e4b17023SJohn Marino gate_strlen, /* gate */
2043e4b17023SJohn Marino tree_ssa_strlen, /* execute */
2044e4b17023SJohn Marino NULL, /* sub */
2045e4b17023SJohn Marino NULL, /* next */
2046e4b17023SJohn Marino 0, /* static_pass_number */
2047e4b17023SJohn Marino TV_TREE_STRLEN, /* tv_id */
2048e4b17023SJohn Marino PROP_cfg | PROP_ssa, /* properties_required */
2049e4b17023SJohn Marino 0, /* properties_provided */
2050e4b17023SJohn Marino 0, /* properties_destroyed */
2051e4b17023SJohn Marino 0, /* todo_flags_start */
2052e4b17023SJohn Marino TODO_ggc_collect
2053e4b17023SJohn Marino | TODO_verify_ssa /* todo_flags_finish */
2054e4b17023SJohn Marino }
2055e4b17023SJohn Marino };
2056