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