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