xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/tree-ssa-strlen.c (revision cef8759bd76c1b621f8eab8faa6f208faabc2e15)
1 /* String length optimization
2    Copyright (C) 2011-2017 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 "backend.h"
25 #include "rtl.h"
26 #include "tree.h"
27 #include "gimple.h"
28 #include "alloc-pool.h"
29 #include "tree-pass.h"
30 #include "ssa.h"
31 #include "cgraph.h"
32 #include "gimple-pretty-print.h"
33 #include "fold-const.h"
34 #include "stor-layout.h"
35 #include "gimple-fold.h"
36 #include "tree-eh.h"
37 #include "gimplify.h"
38 #include "gimple-iterator.h"
39 #include "gimplify-me.h"
40 #include "expr.h"
41 #include "tree-dfa.h"
42 #include "domwalk.h"
43 #include "tree-ssa-propagate.h"
44 #include "params.h"
45 #include "ipa-chkp.h"
46 #include "tree-hash-traits.h"
47 #include "builtins.h"
48 
49 /* A vector indexed by SSA_NAME_VERSION.  0 means unknown, positive value
50    is an index into strinfo vector, negative value stands for
51    string length of a string literal (~strlen).  */
52 static vec<int> ssa_ver_to_stridx;
53 
54 /* Number of currently active string indexes plus one.  */
55 static int max_stridx;
56 
57 /* String information record.  */
58 struct strinfo
59 {
60   /* String length of this string.  */
61   tree length;
62   /* Any of the corresponding pointers for querying alias oracle.  */
63   tree ptr;
64   /* This is used for two things:
65 
66      - To record the statement that should be used for delayed length
67        computations.  We maintain the invariant that all related strinfos
68        have delayed lengths or none do.
69 
70      - To record the malloc or calloc call that produced this result.  */
71   gimple *stmt;
72   /* Pointer to '\0' if known, if NULL, it can be computed as
73      ptr + length.  */
74   tree endptr;
75   /* Reference count.  Any changes to strinfo entry possibly shared
76      with dominating basic blocks need unshare_strinfo first, except
77      for dont_invalidate which affects only the immediately next
78      maybe_invalidate.  */
79   int refcount;
80   /* Copy of index.  get_strinfo (si->idx) should return si;  */
81   int idx;
82   /* These 3 fields are for chaining related string pointers together.
83      E.g. for
84      bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
85      strcpy (c, d); e = c + dl;
86      strinfo(a) -> strinfo(c) -> strinfo(e)
87      All have ->first field equal to strinfo(a)->idx and are doubly
88      chained through prev/next fields.  The later strinfos are required
89      to point into the same string with zero or more bytes after
90      the previous pointer and all bytes in between the two pointers
91      must be non-zero.  Functions like strcpy or memcpy are supposed
92      to adjust all previous strinfo lengths, but not following strinfo
93      lengths (those are uncertain, usually invalidated during
94      maybe_invalidate, except when the alias oracle knows better).
95      Functions like strcat on the other side adjust the whole
96      related strinfo chain.
97      They are updated lazily, so to use the chain the same first fields
98      and si->prev->next == si->idx needs to be verified.  */
99   int first;
100   int next;
101   int prev;
102   /* A flag whether the string is known to be written in the current
103      function.  */
104   bool writable;
105   /* A flag for the next maybe_invalidate that this strinfo shouldn't
106      be invalidated.  Always cleared by maybe_invalidate.  */
107   bool dont_invalidate;
108 };
109 
110 /* Pool for allocating strinfo_struct entries.  */
111 static object_allocator<strinfo> strinfo_pool ("strinfo pool");
112 
113 /* Vector mapping positive string indexes to strinfo, for the
114    current basic block.  The first pointer in the vector is special,
115    it is either NULL, meaning the vector isn't shared, or it is
116    a basic block pointer to the owner basic_block if shared.
117    If some other bb wants to modify the vector, the vector needs
118    to be unshared first, and only the owner bb is supposed to free it.  */
119 static vec<strinfo *, va_heap, vl_embed> *stridx_to_strinfo;
120 
121 /* One OFFSET->IDX mapping.  */
122 struct stridxlist
123 {
124   struct stridxlist *next;
125   HOST_WIDE_INT offset;
126   int idx;
127 };
128 
129 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings.  */
130 struct decl_stridxlist_map
131 {
132   struct tree_map_base base;
133   struct stridxlist list;
134 };
135 
136 /* Hash table for mapping decls to a chained list of offset -> idx
137    mappings.  */
138 static hash_map<tree_decl_hash, stridxlist> *decl_to_stridxlist_htab;
139 
140 /* Obstack for struct stridxlist and struct decl_stridxlist_map.  */
141 static struct obstack stridx_obstack;
142 
143 /* Last memcpy statement if it could be adjusted if the trailing
144    '\0' written is immediately overwritten, or
145    *x = '\0' store that could be removed if it is immediately overwritten.  */
146 struct laststmt_struct
147 {
148   gimple *stmt;
149   tree len;
150   int stridx;
151 } laststmt;
152 
153 static int get_stridx_plus_constant (strinfo *, HOST_WIDE_INT, tree);
154 
155 /* Return strinfo vector entry IDX.  */
156 
157 static inline strinfo *
158 get_strinfo (int idx)
159 {
160   if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
161     return NULL;
162   return (*stridx_to_strinfo)[idx];
163 }
164 
165 /* Get the next strinfo in the chain after SI, or null if none.  */
166 
167 static inline strinfo *
168 get_next_strinfo (strinfo *si)
169 {
170   if (si->next == 0)
171     return NULL;
172   strinfo *nextsi = get_strinfo (si->next);
173   if (nextsi == NULL || nextsi->first != si->first || nextsi->prev != si->idx)
174     return NULL;
175   return nextsi;
176 }
177 
178 /* Helper function for get_stridx.  */
179 
180 static int
181 get_addr_stridx (tree exp, tree ptr)
182 {
183   HOST_WIDE_INT off;
184   struct stridxlist *list, *last = NULL;
185   tree base;
186 
187   if (!decl_to_stridxlist_htab)
188     return 0;
189 
190   base = get_addr_base_and_unit_offset (exp, &off);
191   if (base == NULL || !DECL_P (base))
192     return 0;
193 
194   list = decl_to_stridxlist_htab->get (base);
195   if (list == NULL)
196     return 0;
197 
198   do
199     {
200       if (list->offset == off)
201 	return list->idx;
202       if (list->offset > off)
203 	return 0;
204       last = list;
205       list = list->next;
206     }
207   while (list);
208 
209   if (ptr && last && last->idx > 0)
210     {
211       strinfo *si = get_strinfo (last->idx);
212       if (si
213 	  && si->length
214 	  && TREE_CODE (si->length) == INTEGER_CST
215 	  && compare_tree_int (si->length, off - last->offset) != -1)
216 	return get_stridx_plus_constant (si, off - last->offset, ptr);
217     }
218   return 0;
219 }
220 
221 /* Return string index for EXP.  */
222 
223 static int
224 get_stridx (tree exp)
225 {
226   tree s, o;
227 
228   if (TREE_CODE (exp) == SSA_NAME)
229     {
230       if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)])
231 	return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
232       int i;
233       tree e = exp;
234       HOST_WIDE_INT off = 0;
235       for (i = 0; i < 5; i++)
236 	{
237 	  gimple *def_stmt = SSA_NAME_DEF_STMT (e);
238 	  if (!is_gimple_assign (def_stmt)
239 	      || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR)
240 	    return 0;
241 	  tree rhs1 = gimple_assign_rhs1 (def_stmt);
242 	  tree rhs2 = gimple_assign_rhs2 (def_stmt);
243 	  if (TREE_CODE (rhs1) != SSA_NAME
244 	      || !tree_fits_shwi_p (rhs2))
245 	    return 0;
246 	  HOST_WIDE_INT this_off = tree_to_shwi (rhs2);
247 	  if (this_off < 0)
248 	    return 0;
249 	  off = (unsigned HOST_WIDE_INT) off + this_off;
250 	  if (off < 0)
251 	    return 0;
252 	  if (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)])
253 	    {
254 	      strinfo *si
255 		= get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]);
256 	      if (si
257 		  && si->length
258 		  && TREE_CODE (si->length) == INTEGER_CST
259 		  && compare_tree_int (si->length, off) != -1)
260 		return get_stridx_plus_constant (si, off, exp);
261 	    }
262 	  e = rhs1;
263 	}
264       return 0;
265     }
266 
267   if (TREE_CODE (exp) == ADDR_EXPR)
268     {
269       int idx = get_addr_stridx (TREE_OPERAND (exp, 0), exp);
270       if (idx != 0)
271 	return idx;
272     }
273 
274   s = string_constant (exp, &o);
275   if (s != NULL_TREE
276       && (o == NULL_TREE || tree_fits_shwi_p (o))
277       && TREE_STRING_LENGTH (s) > 0)
278     {
279       HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
280       const char *p = TREE_STRING_POINTER (s);
281       int max = TREE_STRING_LENGTH (s) - 1;
282 
283       if (p[max] == '\0' && offset >= 0 && offset <= max)
284 	return ~(int) strlen (p + offset);
285     }
286   return 0;
287 }
288 
289 /* Return true if strinfo vector is shared with the immediate dominator.  */
290 
291 static inline bool
292 strinfo_shared (void)
293 {
294   return vec_safe_length (stridx_to_strinfo)
295 	 && (*stridx_to_strinfo)[0] != NULL;
296 }
297 
298 /* Unshare strinfo vector that is shared with the immediate dominator.  */
299 
300 static void
301 unshare_strinfo_vec (void)
302 {
303   strinfo *si;
304   unsigned int i = 0;
305 
306   gcc_assert (strinfo_shared ());
307   stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo);
308   for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
309     if (si != NULL)
310       si->refcount++;
311   (*stridx_to_strinfo)[0] = NULL;
312 }
313 
314 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
315    Return a pointer to the location where the string index can
316    be stored (if 0) or is stored, or NULL if this can't be tracked.  */
317 
318 static int *
319 addr_stridxptr (tree exp)
320 {
321   HOST_WIDE_INT off;
322 
323   tree base = get_addr_base_and_unit_offset (exp, &off);
324   if (base == NULL_TREE || !DECL_P (base))
325     return NULL;
326 
327   if (!decl_to_stridxlist_htab)
328     {
329       decl_to_stridxlist_htab
330        	= new hash_map<tree_decl_hash, stridxlist> (64);
331       gcc_obstack_init (&stridx_obstack);
332     }
333 
334   bool existed;
335   stridxlist *list = &decl_to_stridxlist_htab->get_or_insert (base, &existed);
336   if (existed)
337     {
338       int i;
339       stridxlist *before = NULL;
340       for (i = 0; i < 32; i++)
341 	{
342 	  if (list->offset == off)
343 	    return &list->idx;
344 	  if (list->offset > off && before == NULL)
345 	    before = list;
346 	  if (list->next == NULL)
347 	    break;
348 	  list = list->next;
349 	}
350       if (i == 32)
351 	return NULL;
352       if (before)
353 	{
354 	  list = before;
355 	  before = XOBNEW (&stridx_obstack, struct stridxlist);
356 	  *before = *list;
357 	  list->next = before;
358 	  list->offset = off;
359 	  list->idx = 0;
360 	  return &list->idx;
361 	}
362       list->next = XOBNEW (&stridx_obstack, struct stridxlist);
363       list = list->next;
364     }
365 
366   list->next = NULL;
367   list->offset = off;
368   list->idx = 0;
369   return &list->idx;
370 }
371 
372 /* Create a new string index, or return 0 if reached limit.  */
373 
374 static int
375 new_stridx (tree exp)
376 {
377   int idx;
378   if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
379     return 0;
380   if (TREE_CODE (exp) == SSA_NAME)
381     {
382       if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
383 	return 0;
384       idx = max_stridx++;
385       ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx;
386       return idx;
387     }
388   if (TREE_CODE (exp) == ADDR_EXPR)
389     {
390       int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
391       if (pidx != NULL)
392 	{
393 	  gcc_assert (*pidx == 0);
394 	  *pidx = max_stridx++;
395 	  return *pidx;
396 	}
397     }
398   return 0;
399 }
400 
401 /* Like new_stridx, but for ADDR_EXPR's operand instead.  */
402 
403 static int
404 new_addr_stridx (tree exp)
405 {
406   int *pidx;
407   if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
408     return 0;
409   pidx = addr_stridxptr (exp);
410   if (pidx != NULL)
411     {
412       gcc_assert (*pidx == 0);
413       *pidx = max_stridx++;
414       return *pidx;
415     }
416   return 0;
417 }
418 
419 /* Create a new strinfo.  */
420 
421 static strinfo *
422 new_strinfo (tree ptr, int idx, tree length)
423 {
424   strinfo *si = strinfo_pool.allocate ();
425   si->length = length;
426   si->ptr = ptr;
427   si->stmt = NULL;
428   si->endptr = NULL_TREE;
429   si->refcount = 1;
430   si->idx = idx;
431   si->first = 0;
432   si->prev = 0;
433   si->next = 0;
434   si->writable = false;
435   si->dont_invalidate = false;
436   return si;
437 }
438 
439 /* Decrease strinfo refcount and free it if not referenced anymore.  */
440 
441 static inline void
442 free_strinfo (strinfo *si)
443 {
444   if (si && --si->refcount == 0)
445     strinfo_pool.remove (si);
446 }
447 
448 /* Set strinfo in the vector entry IDX to SI.  */
449 
450 static inline void
451 set_strinfo (int idx, strinfo *si)
452 {
453   if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0])
454     unshare_strinfo_vec ();
455   if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
456     vec_safe_grow_cleared (stridx_to_strinfo, idx + 1);
457   (*stridx_to_strinfo)[idx] = si;
458 }
459 
460 /* Return the first strinfo in the related strinfo chain
461    if all strinfos in between belong to the chain, otherwise NULL.  */
462 
463 static strinfo *
464 verify_related_strinfos (strinfo *origsi)
465 {
466   strinfo *si = origsi, *psi;
467 
468   if (origsi->first == 0)
469     return NULL;
470   for (; si->prev; si = psi)
471     {
472       if (si->first != origsi->first)
473 	return NULL;
474       psi = get_strinfo (si->prev);
475       if (psi == NULL)
476 	return NULL;
477       if (psi->next != si->idx)
478 	return NULL;
479     }
480   if (si->idx != si->first)
481     return NULL;
482   return si;
483 }
484 
485 /* Set SI's endptr to ENDPTR and compute its length based on SI->ptr.
486    Use LOC for folding.  */
487 
488 static void
489 set_endptr_and_length (location_t loc, strinfo *si, tree endptr)
490 {
491   si->endptr = endptr;
492   si->stmt = NULL;
493   tree start_as_size = fold_convert_loc (loc, size_type_node, si->ptr);
494   tree end_as_size = fold_convert_loc (loc, size_type_node, endptr);
495   si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
496 				end_as_size, start_as_size);
497 }
498 
499 /* Return string length, or NULL if it can't be computed.  */
500 
501 static tree
502 get_string_length (strinfo *si)
503 {
504   if (si->length)
505     return si->length;
506 
507   if (si->stmt)
508     {
509       gimple *stmt = si->stmt, *lenstmt;
510       bool with_bounds = gimple_call_with_bounds_p (stmt);
511       tree callee, lhs, fn, tem;
512       location_t loc;
513       gimple_stmt_iterator gsi;
514 
515       gcc_assert (is_gimple_call (stmt));
516       callee = gimple_call_fndecl (stmt);
517       gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
518       lhs = gimple_call_lhs (stmt);
519       /* unshare_strinfo is intentionally not called here.  The (delayed)
520 	 transformation of strcpy or strcat into stpcpy is done at the place
521 	 of the former strcpy/strcat call and so can affect all the strinfos
522 	 with the same stmt.  If they were unshared before and transformation
523 	 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
524 	 just compute the right length.  */
525       switch (DECL_FUNCTION_CODE (callee))
526 	{
527 	case BUILT_IN_STRCAT:
528 	case BUILT_IN_STRCAT_CHK:
529 	case BUILT_IN_STRCAT_CHKP:
530 	case BUILT_IN_STRCAT_CHK_CHKP:
531 	  gsi = gsi_for_stmt (stmt);
532 	  fn = builtin_decl_implicit (BUILT_IN_STRLEN);
533 	  gcc_assert (lhs == NULL_TREE);
534 	  tem = unshare_expr (gimple_call_arg (stmt, 0));
535 	  if (with_bounds)
536 	    {
537 	      lenstmt = gimple_build_call (chkp_maybe_create_clone (fn)->decl,
538 					   2, tem, gimple_call_arg (stmt, 1));
539 	      gimple_call_set_with_bounds (lenstmt, true);
540 	    }
541 	  else
542 	    lenstmt = gimple_build_call (fn, 1, tem);
543 	  lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt);
544 	  gimple_call_set_lhs (lenstmt, lhs);
545 	  gimple_set_vuse (lenstmt, gimple_vuse (stmt));
546 	  gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
547 	  tem = gimple_call_arg (stmt, 0);
548           if (!ptrofftype_p (TREE_TYPE (lhs)))
549             {
550               lhs = convert_to_ptrofftype (lhs);
551               lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE,
552                                               true, GSI_SAME_STMT);
553             }
554 	  lenstmt = gimple_build_assign
555 			(make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0))),
556 			 POINTER_PLUS_EXPR,tem, lhs);
557 	  gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
558 	  gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
559 	  lhs = NULL_TREE;
560 	  /* FALLTHRU */
561 	case BUILT_IN_STRCPY:
562 	case BUILT_IN_STRCPY_CHK:
563 	case BUILT_IN_STRCPY_CHKP:
564 	case BUILT_IN_STRCPY_CHK_CHKP:
565 	  gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
566 	  if (gimple_call_num_args (stmt) == (with_bounds ? 4 : 2))
567 	    fn = builtin_decl_implicit (BUILT_IN_STPCPY);
568 	  else
569 	    fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
570 	  if (with_bounds)
571 	    fn = chkp_maybe_create_clone (fn)->decl;
572 	  gcc_assert (lhs == NULL_TREE);
573 	  if (dump_file && (dump_flags & TDF_DETAILS) != 0)
574 	    {
575 	      fprintf (dump_file, "Optimizing: ");
576 	      print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
577 	    }
578 	  gimple_call_set_fndecl (stmt, fn);
579 	  lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
580 	  gimple_call_set_lhs (stmt, lhs);
581 	  update_stmt (stmt);
582 	  if (dump_file && (dump_flags & TDF_DETAILS) != 0)
583 	    {
584 	      fprintf (dump_file, "into: ");
585 	      print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
586 	    }
587 	  /* FALLTHRU */
588 	case BUILT_IN_STPCPY:
589 	case BUILT_IN_STPCPY_CHK:
590 	case BUILT_IN_STPCPY_CHKP:
591 	case BUILT_IN_STPCPY_CHK_CHKP:
592 	  gcc_assert (lhs != NULL_TREE);
593 	  loc = gimple_location (stmt);
594 	  set_endptr_and_length (loc, si, lhs);
595 	  for (strinfo *chainsi = verify_related_strinfos (si);
596 	       chainsi != NULL;
597 	       chainsi = get_next_strinfo (chainsi))
598 	    if (chainsi->length == NULL)
599 	      set_endptr_and_length (loc, chainsi, lhs);
600 	  break;
601 	case BUILT_IN_MALLOC:
602 	  break;
603 	/* BUILT_IN_CALLOC always has si->length set.  */
604 	default:
605 	  gcc_unreachable ();
606 	  break;
607 	}
608     }
609 
610   return si->length;
611 }
612 
613 /* Invalidate string length information for strings whose length
614    might change due to stores in stmt.  */
615 
616 static bool
617 maybe_invalidate (gimple *stmt)
618 {
619   strinfo *si;
620   unsigned int i;
621   bool nonempty = false;
622 
623   for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
624     if (si != NULL)
625       {
626 	if (!si->dont_invalidate)
627 	  {
628 	    ao_ref r;
629 	    /* Do not use si->length.  */
630 	    ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
631 	    if (stmt_may_clobber_ref_p_1 (stmt, &r))
632 	      {
633 		set_strinfo (i, NULL);
634 		free_strinfo (si);
635 		continue;
636 	      }
637 	  }
638 	si->dont_invalidate = false;
639 	nonempty = true;
640       }
641   return nonempty;
642 }
643 
644 /* Unshare strinfo record SI, if it has refcount > 1 or
645    if stridx_to_strinfo vector is shared with some other
646    bbs.  */
647 
648 static strinfo *
649 unshare_strinfo (strinfo *si)
650 {
651   strinfo *nsi;
652 
653   if (si->refcount == 1 && !strinfo_shared ())
654     return si;
655 
656   nsi = new_strinfo (si->ptr, si->idx, si->length);
657   nsi->stmt = si->stmt;
658   nsi->endptr = si->endptr;
659   nsi->first = si->first;
660   nsi->prev = si->prev;
661   nsi->next = si->next;
662   nsi->writable = si->writable;
663   set_strinfo (si->idx, nsi);
664   free_strinfo (si);
665   return nsi;
666 }
667 
668 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
669    strinfo if there is any.  Return it's idx, or 0 if no strinfo has
670    been created.  */
671 
672 static int
673 get_stridx_plus_constant (strinfo *basesi, HOST_WIDE_INT off, tree ptr)
674 {
675   if (TREE_CODE (ptr) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
676     return 0;
677 
678   if (basesi->length == NULL_TREE
679       || TREE_CODE (basesi->length) != INTEGER_CST
680       || compare_tree_int (basesi->length, off) == -1
681       || !tree_fits_shwi_p (basesi->length))
682     return 0;
683 
684   HOST_WIDE_INT len = tree_to_shwi (basesi->length) - off;
685   strinfo *si = basesi, *chainsi;
686   if (si->first || si->prev || si->next)
687     si = verify_related_strinfos (basesi);
688   if (si == NULL
689       || si->length == NULL_TREE
690       || TREE_CODE (si->length) != INTEGER_CST)
691     return 0;
692 
693   if (TREE_CODE (ptr) == SSA_NAME
694       && ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
695     ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
696 
697   gcc_checking_assert (compare_tree_int (si->length, off) != -1);
698   for (chainsi = si; chainsi->next; chainsi = si)
699     {
700       si = get_strinfo (chainsi->next);
701       if (si == NULL
702 	  || si->first != chainsi->first
703 	  || si->prev != chainsi->idx
704 	  || si->length == NULL_TREE
705 	  || TREE_CODE (si->length) != INTEGER_CST)
706 	break;
707       int r = compare_tree_int (si->length, len);
708       if (r != 1)
709 	{
710 	  if (r == 0)
711 	    {
712 	      if (TREE_CODE (ptr) == SSA_NAME)
713 		ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = si->idx;
714 	      else
715 		{
716 		  int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
717 		  if (pidx != NULL && *pidx == 0)
718 		    *pidx = si->idx;
719 		}
720 	      return si->idx;
721 	    }
722 	  break;
723 	}
724     }
725 
726   int idx = new_stridx (ptr);
727   if (idx == 0)
728     return 0;
729   si = new_strinfo (ptr, idx, build_int_cst (size_type_node, len));
730   set_strinfo (idx, si);
731   if (chainsi->next)
732     {
733       strinfo *nextsi = unshare_strinfo (get_strinfo (chainsi->next));
734       si->next = nextsi->idx;
735       nextsi->prev = idx;
736     }
737   chainsi = unshare_strinfo (chainsi);
738   if (chainsi->first == 0)
739     chainsi->first = chainsi->idx;
740   chainsi->next = idx;
741   if (chainsi->endptr == NULL_TREE && len == 0)
742     chainsi->endptr = ptr;
743   si->endptr = chainsi->endptr;
744   si->prev = chainsi->idx;
745   si->first = chainsi->first;
746   si->writable = chainsi->writable;
747   return si->idx;
748 }
749 
750 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
751    to a zero-length string and if possible chain it to a related strinfo
752    chain whose part is or might be CHAINSI.  */
753 
754 static strinfo *
755 zero_length_string (tree ptr, strinfo *chainsi)
756 {
757   strinfo *si;
758   int idx;
759   if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
760     ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
761   gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
762 		       && ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] == 0);
763 
764   if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
765     return NULL;
766   if (chainsi != NULL)
767     {
768       si = verify_related_strinfos (chainsi);
769       if (si)
770 	{
771 	  chainsi = si;
772 	  for (; chainsi->next; chainsi = si)
773 	    {
774 	      if (chainsi->endptr == NULL_TREE)
775 		{
776 		  chainsi = unshare_strinfo (chainsi);
777 		  chainsi->endptr = ptr;
778 		}
779 	      si = get_strinfo (chainsi->next);
780 	      if (si == NULL
781 		  || si->first != chainsi->first
782 		  || si->prev != chainsi->idx)
783 		break;
784 	    }
785 	  gcc_assert (chainsi->length || chainsi->stmt);
786 	  if (chainsi->endptr == NULL_TREE)
787 	    {
788 	      chainsi = unshare_strinfo (chainsi);
789 	      chainsi->endptr = ptr;
790 	    }
791 	  if (chainsi->length && integer_zerop (chainsi->length))
792 	    {
793 	      if (chainsi->next)
794 		{
795 		  chainsi = unshare_strinfo (chainsi);
796 		  chainsi->next = 0;
797 		}
798 	      ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
799 	      return chainsi;
800 	    }
801 	}
802       else if (chainsi->first || chainsi->prev || chainsi->next)
803 	{
804 	  chainsi = unshare_strinfo (chainsi);
805 	  chainsi->first = 0;
806 	  chainsi->prev = 0;
807 	  chainsi->next = 0;
808 	}
809     }
810   idx = new_stridx (ptr);
811   if (idx == 0)
812     return NULL;
813   si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0));
814   set_strinfo (idx, si);
815   si->endptr = ptr;
816   if (chainsi != NULL)
817     {
818       chainsi = unshare_strinfo (chainsi);
819       if (chainsi->first == 0)
820 	chainsi->first = chainsi->idx;
821       chainsi->next = idx;
822       if (chainsi->endptr == NULL_TREE)
823 	chainsi->endptr = ptr;
824       si->prev = chainsi->idx;
825       si->first = chainsi->first;
826       si->writable = chainsi->writable;
827     }
828   return si;
829 }
830 
831 /* For strinfo ORIGSI whose length has been just updated
832    update also related strinfo lengths (add ADJ to each,
833    but don't adjust ORIGSI).  */
834 
835 static void
836 adjust_related_strinfos (location_t loc, strinfo *origsi, tree adj)
837 {
838   strinfo *si = verify_related_strinfos (origsi);
839 
840   if (si == NULL)
841     return;
842 
843   while (1)
844     {
845       strinfo *nsi;
846 
847       if (si != origsi)
848 	{
849 	  tree tem;
850 
851 	  si = unshare_strinfo (si);
852 	  if (si->length)
853 	    {
854 	      tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
855 	      si->length = fold_build2_loc (loc, PLUS_EXPR,
856 					    TREE_TYPE (si->length), si->length,
857 					    tem);
858 	    }
859 	  else if (si->stmt != NULL)
860 	    /* Delayed length computation is unaffected.  */
861 	    ;
862 	  else
863 	    gcc_unreachable ();
864 
865 	  si->endptr = NULL_TREE;
866 	  si->dont_invalidate = true;
867 	}
868       if (si->next == 0)
869 	return;
870       nsi = get_strinfo (si->next);
871       if (nsi == NULL
872 	  || nsi->first != si->first
873 	  || nsi->prev != si->idx)
874 	return;
875       si = nsi;
876     }
877 }
878 
879 /* Find if there are other SSA_NAME pointers equal to PTR
880    for which we don't track their string lengths yet.  If so, use
881    IDX for them.  */
882 
883 static void
884 find_equal_ptrs (tree ptr, int idx)
885 {
886   if (TREE_CODE (ptr) != SSA_NAME)
887     return;
888   while (1)
889     {
890       gimple *stmt = SSA_NAME_DEF_STMT (ptr);
891       if (!is_gimple_assign (stmt))
892 	return;
893       ptr = gimple_assign_rhs1 (stmt);
894       switch (gimple_assign_rhs_code (stmt))
895 	{
896 	case SSA_NAME:
897 	  break;
898 	CASE_CONVERT:
899 	  if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
900 	    return;
901 	  if (TREE_CODE (ptr) == SSA_NAME)
902 	    break;
903 	  if (TREE_CODE (ptr) != ADDR_EXPR)
904 	    return;
905 	  /* FALLTHRU */
906 	case ADDR_EXPR:
907 	  {
908 	    int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
909 	    if (pidx != NULL && *pidx == 0)
910 	      *pidx = idx;
911 	    return;
912 	  }
913 	default:
914 	  return;
915 	}
916 
917       /* We might find an endptr created in this pass.  Grow the
918 	 vector in that case.  */
919       if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
920 	ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
921 
922       if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
923 	return;
924       ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
925     }
926 }
927 
928 /* Return true if STMT is a call to a builtin function with the right
929    arguments and attributes that should be considered for optimization
930    by this pass.  */
931 
932 static bool
933 valid_builtin_call (gimple *stmt)
934 {
935   if (!gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
936     return false;
937 
938   tree callee = gimple_call_fndecl (stmt);
939   tree decl = builtin_decl_explicit (DECL_FUNCTION_CODE (callee));
940   if (decl
941       && decl != callee
942       && !gimple_builtin_call_types_compatible_p (stmt, decl))
943     return false;
944 
945   switch (DECL_FUNCTION_CODE (callee))
946     {
947     case BUILT_IN_MEMCMP:
948     case BUILT_IN_MEMCMP_EQ:
949     case BUILT_IN_STRCMP:
950     case BUILT_IN_STRNCMP:
951     case BUILT_IN_STRCHR:
952     case BUILT_IN_STRCHR_CHKP:
953     case BUILT_IN_STRLEN:
954     case BUILT_IN_STRLEN_CHKP:
955       /* The above functions should be pure.  Punt if they aren't.  */
956       if (gimple_vdef (stmt) || gimple_vuse (stmt) == NULL_TREE)
957 	return false;
958       break;
959 
960     case BUILT_IN_CALLOC:
961     case BUILT_IN_MALLOC:
962     case BUILT_IN_MEMCPY:
963     case BUILT_IN_MEMCPY_CHK:
964     case BUILT_IN_MEMCPY_CHKP:
965     case BUILT_IN_MEMCPY_CHK_CHKP:
966     case BUILT_IN_MEMPCPY:
967     case BUILT_IN_MEMPCPY_CHK:
968     case BUILT_IN_MEMPCPY_CHKP:
969     case BUILT_IN_MEMPCPY_CHK_CHKP:
970     case BUILT_IN_MEMSET:
971     case BUILT_IN_STPCPY:
972     case BUILT_IN_STPCPY_CHK:
973     case BUILT_IN_STPCPY_CHKP:
974     case BUILT_IN_STPCPY_CHK_CHKP:
975     case BUILT_IN_STPNCPY:
976     case BUILT_IN_STPNCPY_CHK:
977     case BUILT_IN_STRCAT:
978     case BUILT_IN_STRCAT_CHK:
979     case BUILT_IN_STRCAT_CHKP:
980     case BUILT_IN_STRCAT_CHK_CHKP:
981     case BUILT_IN_STRCPY:
982     case BUILT_IN_STRCPY_CHK:
983     case BUILT_IN_STRCPY_CHKP:
984     case BUILT_IN_STRCPY_CHK_CHKP:
985     case BUILT_IN_STRNCAT:
986     case BUILT_IN_STRNCAT_CHK:
987     case BUILT_IN_STRNCPY:
988     case BUILT_IN_STRNCPY_CHK:
989       /* The above functions should be neither const nor pure.  Punt if they
990 	 aren't.  */
991       if (gimple_vdef (stmt) == NULL_TREE || gimple_vuse (stmt) == NULL_TREE)
992 	return false;
993       break;
994 
995     default:
996       break;
997     }
998 
999   return true;
1000 }
1001 
1002 /* If the last .MEM setter statement before STMT is
1003    memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
1004    and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
1005    just memcpy (x, y, strlen (y)).  SI must be the zero length
1006    strinfo.  */
1007 
1008 static void
1009 adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
1010 {
1011   tree vuse, callee, len;
1012   struct laststmt_struct last = laststmt;
1013   strinfo *lastsi, *firstsi;
1014   unsigned len_arg_no = 2;
1015 
1016   laststmt.stmt = NULL;
1017   laststmt.len = NULL_TREE;
1018   laststmt.stridx = 0;
1019 
1020   if (last.stmt == NULL)
1021     return;
1022 
1023   vuse = gimple_vuse (stmt);
1024   if (vuse == NULL_TREE
1025       || SSA_NAME_DEF_STMT (vuse) != last.stmt
1026       || !has_single_use (vuse))
1027     return;
1028 
1029   gcc_assert (last.stridx > 0);
1030   lastsi = get_strinfo (last.stridx);
1031   if (lastsi == NULL)
1032     return;
1033 
1034   if (lastsi != si)
1035     {
1036       if (lastsi->first == 0 || lastsi->first != si->first)
1037 	return;
1038 
1039       firstsi = verify_related_strinfos (si);
1040       if (firstsi == NULL)
1041 	return;
1042       while (firstsi != lastsi)
1043 	{
1044 	  strinfo *nextsi;
1045 	  if (firstsi->next == 0)
1046 	    return;
1047 	  nextsi = get_strinfo (firstsi->next);
1048 	  if (nextsi == NULL
1049 	      || nextsi->prev != firstsi->idx
1050 	      || nextsi->first != si->first)
1051 	    return;
1052 	  firstsi = nextsi;
1053 	}
1054     }
1055 
1056   if (!is_strcat)
1057     {
1058       if (si->length == NULL_TREE || !integer_zerop (si->length))
1059 	return;
1060     }
1061 
1062   if (is_gimple_assign (last.stmt))
1063     {
1064       gimple_stmt_iterator gsi;
1065 
1066       if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
1067 	return;
1068       if (stmt_could_throw_p (last.stmt))
1069 	return;
1070       gsi = gsi_for_stmt (last.stmt);
1071       unlink_stmt_vdef (last.stmt);
1072       release_defs (last.stmt);
1073       gsi_remove (&gsi, true);
1074       return;
1075     }
1076 
1077   if (!valid_builtin_call (last.stmt))
1078     return;
1079 
1080   callee = gimple_call_fndecl (last.stmt);
1081   switch (DECL_FUNCTION_CODE (callee))
1082     {
1083     case BUILT_IN_MEMCPY:
1084     case BUILT_IN_MEMCPY_CHK:
1085       break;
1086     case BUILT_IN_MEMCPY_CHKP:
1087     case BUILT_IN_MEMCPY_CHK_CHKP:
1088       len_arg_no = 4;
1089       break;
1090     default:
1091       return;
1092     }
1093 
1094   len = gimple_call_arg (last.stmt, len_arg_no);
1095   if (tree_fits_uhwi_p (len))
1096     {
1097       if (!tree_fits_uhwi_p (last.len)
1098 	  || integer_zerop (len)
1099 	  || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1)
1100 	return;
1101       /* Don't adjust the length if it is divisible by 4, it is more efficient
1102 	 to store the extra '\0' in that case.  */
1103       if ((tree_to_uhwi (len) & 3) == 0)
1104 	return;
1105     }
1106   else if (TREE_CODE (len) == SSA_NAME)
1107     {
1108       gimple *def_stmt = SSA_NAME_DEF_STMT (len);
1109       if (!is_gimple_assign (def_stmt)
1110 	  || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1111 	  || gimple_assign_rhs1 (def_stmt) != last.len
1112 	  || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1113 	return;
1114     }
1115   else
1116     return;
1117 
1118   gimple_call_set_arg (last.stmt, len_arg_no, last.len);
1119   update_stmt (last.stmt);
1120 }
1121 
1122 /* Handle a strlen call.  If strlen of the argument is known, replace
1123    the strlen call with the known value, otherwise remember that strlen
1124    of the argument is stored in the lhs SSA_NAME.  */
1125 
1126 static void
1127 handle_builtin_strlen (gimple_stmt_iterator *gsi)
1128 {
1129   int idx;
1130   tree src;
1131   gimple *stmt = gsi_stmt (*gsi);
1132   tree lhs = gimple_call_lhs (stmt);
1133 
1134   if (lhs == NULL_TREE)
1135     return;
1136 
1137   src = gimple_call_arg (stmt, 0);
1138   idx = get_stridx (src);
1139   if (idx)
1140     {
1141       strinfo *si = NULL;
1142       tree rhs;
1143 
1144       if (idx < 0)
1145 	rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
1146       else
1147 	{
1148 	  rhs = NULL_TREE;
1149 	  si = get_strinfo (idx);
1150 	  if (si != NULL)
1151 	    rhs = get_string_length (si);
1152 	}
1153       if (rhs != NULL_TREE)
1154 	{
1155 	  if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1156 	    {
1157 	      fprintf (dump_file, "Optimizing: ");
1158 	      print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1159 	    }
1160 	  rhs = unshare_expr (rhs);
1161 	  if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
1162 	    rhs = fold_convert_loc (gimple_location (stmt),
1163 				    TREE_TYPE (lhs), rhs);
1164 	  if (!update_call_from_tree (gsi, rhs))
1165 	    gimplify_and_update_call_from_tree (gsi, rhs);
1166 	  stmt = gsi_stmt (*gsi);
1167 	  update_stmt (stmt);
1168 	  if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1169 	    {
1170 	      fprintf (dump_file, "into: ");
1171 	      print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1172 	    }
1173 	  if (si != NULL
1174 	      && TREE_CODE (si->length) != SSA_NAME
1175 	      && TREE_CODE (si->length) != INTEGER_CST
1176 	      && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1177 	    {
1178 	      si = unshare_strinfo (si);
1179 	      si->length = lhs;
1180 	    }
1181 	  return;
1182 	}
1183     }
1184   if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1185     return;
1186   if (idx == 0)
1187     idx = new_stridx (src);
1188   else if (get_strinfo (idx) != NULL)
1189     return;
1190   if (idx)
1191     {
1192       strinfo *si = new_strinfo (src, idx, lhs);
1193       set_strinfo (idx, si);
1194       find_equal_ptrs (src, idx);
1195     }
1196 }
1197 
1198 /* Handle a strchr call.  If strlen of the first argument is known, replace
1199    the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1200    that lhs of the call is endptr and strlen of the argument is endptr - x.  */
1201 
1202 static void
1203 handle_builtin_strchr (gimple_stmt_iterator *gsi)
1204 {
1205   int idx;
1206   tree src;
1207   gimple *stmt = gsi_stmt (*gsi);
1208   tree lhs = gimple_call_lhs (stmt);
1209   bool with_bounds = gimple_call_with_bounds_p (stmt);
1210 
1211   if (lhs == NULL_TREE)
1212     return;
1213 
1214   if (!integer_zerop (gimple_call_arg (stmt, with_bounds ? 2 : 1)))
1215     return;
1216 
1217   src = gimple_call_arg (stmt, 0);
1218   idx = get_stridx (src);
1219   if (idx)
1220     {
1221       strinfo *si = NULL;
1222       tree rhs;
1223 
1224       if (idx < 0)
1225 	rhs = build_int_cst (size_type_node, ~idx);
1226       else
1227 	{
1228 	  rhs = NULL_TREE;
1229 	  si = get_strinfo (idx);
1230 	  if (si != NULL)
1231 	    rhs = get_string_length (si);
1232 	}
1233       if (rhs != NULL_TREE)
1234 	{
1235 	  location_t loc = gimple_location (stmt);
1236 
1237 	  if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1238 	    {
1239 	      fprintf (dump_file, "Optimizing: ");
1240 	      print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1241 	    }
1242 	  if (si != NULL && si->endptr != NULL_TREE)
1243 	    {
1244 	      rhs = unshare_expr (si->endptr);
1245 	      if (!useless_type_conversion_p (TREE_TYPE (lhs),
1246 					      TREE_TYPE (rhs)))
1247 		rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1248 	    }
1249 	  else
1250 	    {
1251 	      rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
1252 	      rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1253 				     TREE_TYPE (src), src, rhs);
1254 	      if (!useless_type_conversion_p (TREE_TYPE (lhs),
1255 					      TREE_TYPE (rhs)))
1256 		rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1257 	    }
1258 	  if (!update_call_from_tree (gsi, rhs))
1259 	    gimplify_and_update_call_from_tree (gsi, rhs);
1260 	  stmt = gsi_stmt (*gsi);
1261 	  update_stmt (stmt);
1262 	  if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1263 	    {
1264 	      fprintf (dump_file, "into: ");
1265 	      print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1266 	    }
1267 	  if (si != NULL
1268 	      && si->endptr == NULL_TREE
1269 	      && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1270 	    {
1271 	      si = unshare_strinfo (si);
1272 	      si->endptr = lhs;
1273 	    }
1274 	  zero_length_string (lhs, si);
1275 	  return;
1276 	}
1277     }
1278   if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1279     return;
1280   if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1281     {
1282       if (idx == 0)
1283 	idx = new_stridx (src);
1284       else if (get_strinfo (idx) != NULL)
1285 	{
1286 	  zero_length_string (lhs, NULL);
1287 	  return;
1288 	}
1289       if (idx)
1290 	{
1291 	  location_t loc = gimple_location (stmt);
1292 	  tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1293 	  tree srcu = fold_convert_loc (loc, size_type_node, src);
1294 	  tree length = fold_build2_loc (loc, MINUS_EXPR,
1295 					 size_type_node, lhsu, srcu);
1296 	  strinfo *si = new_strinfo (src, idx, length);
1297 	  si->endptr = lhs;
1298 	  set_strinfo (idx, si);
1299 	  find_equal_ptrs (src, idx);
1300 	  zero_length_string (lhs, si);
1301 	}
1302     }
1303   else
1304     zero_length_string (lhs, NULL);
1305 }
1306 
1307 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1308    If strlen of the second argument is known, strlen of the first argument
1309    is the same after this call.  Furthermore, attempt to convert it to
1310    memcpy.  */
1311 
1312 static void
1313 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1314 {
1315   int idx, didx;
1316   tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1317   bool success;
1318   gimple *stmt = gsi_stmt (*gsi);
1319   strinfo *si, *dsi, *olddsi, *zsi;
1320   location_t loc;
1321   bool with_bounds = gimple_call_with_bounds_p (stmt);
1322 
1323   src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1324   dst = gimple_call_arg (stmt, 0);
1325   lhs = gimple_call_lhs (stmt);
1326   idx = get_stridx (src);
1327   si = NULL;
1328   if (idx > 0)
1329     si = get_strinfo (idx);
1330 
1331   didx = get_stridx (dst);
1332   olddsi = NULL;
1333   oldlen = NULL_TREE;
1334   if (didx > 0)
1335     olddsi = get_strinfo (didx);
1336   else if (didx < 0)
1337     return;
1338 
1339   if (olddsi != NULL)
1340     adjust_last_stmt (olddsi, stmt, false);
1341 
1342   srclen = NULL_TREE;
1343   if (si != NULL)
1344     srclen = get_string_length (si);
1345   else if (idx < 0)
1346     srclen = build_int_cst (size_type_node, ~idx);
1347 
1348   loc = gimple_location (stmt);
1349   if (srclen == NULL_TREE)
1350     switch (bcode)
1351       {
1352       case BUILT_IN_STRCPY:
1353       case BUILT_IN_STRCPY_CHK:
1354       case BUILT_IN_STRCPY_CHKP:
1355       case BUILT_IN_STRCPY_CHK_CHKP:
1356 	if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1357 	  return;
1358 	break;
1359       case BUILT_IN_STPCPY:
1360       case BUILT_IN_STPCPY_CHK:
1361       case BUILT_IN_STPCPY_CHKP:
1362       case BUILT_IN_STPCPY_CHK_CHKP:
1363 	if (lhs == NULL_TREE)
1364 	  return;
1365 	else
1366 	  {
1367 	    tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1368 	    srclen = fold_convert_loc (loc, size_type_node, dst);
1369 	    srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1370 				      lhsuint, srclen);
1371 	  }
1372 	break;
1373       default:
1374 	gcc_unreachable ();
1375       }
1376 
1377   if (didx == 0)
1378     {
1379       didx = new_stridx (dst);
1380       if (didx == 0)
1381 	return;
1382     }
1383   if (olddsi != NULL)
1384     {
1385       oldlen = olddsi->length;
1386       dsi = unshare_strinfo (olddsi);
1387       dsi->length = srclen;
1388       /* Break the chain, so adjust_related_strinfo on later pointers in
1389 	 the chain won't adjust this one anymore.  */
1390       dsi->next = 0;
1391       dsi->stmt = NULL;
1392       dsi->endptr = NULL_TREE;
1393     }
1394   else
1395     {
1396       dsi = new_strinfo (dst, didx, srclen);
1397       set_strinfo (didx, dsi);
1398       find_equal_ptrs (dst, didx);
1399     }
1400   dsi->writable = true;
1401   dsi->dont_invalidate = true;
1402 
1403   if (dsi->length == NULL_TREE)
1404     {
1405       strinfo *chainsi;
1406 
1407       /* If string length of src is unknown, use delayed length
1408 	 computation.  If string lenth of dst will be needed, it
1409 	 can be computed by transforming this strcpy call into
1410 	 stpcpy and subtracting dst from the return value.  */
1411 
1412       /* Look for earlier strings whose length could be determined if
1413 	 this strcpy is turned into an stpcpy.  */
1414 
1415       if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1416 	{
1417 	  for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1418 	    {
1419 	      /* When setting a stmt for delayed length computation
1420 		 prevent all strinfos through dsi from being
1421 		 invalidated.  */
1422 	      chainsi = unshare_strinfo (chainsi);
1423 	      chainsi->stmt = stmt;
1424 	      chainsi->length = NULL_TREE;
1425 	      chainsi->endptr = NULL_TREE;
1426 	      chainsi->dont_invalidate = true;
1427 	    }
1428 	}
1429       dsi->stmt = stmt;
1430       return;
1431     }
1432 
1433   if (olddsi != NULL)
1434     {
1435       tree adj = NULL_TREE;
1436       if (oldlen == NULL_TREE)
1437 	;
1438       else if (integer_zerop (oldlen))
1439 	adj = srclen;
1440       else if (TREE_CODE (oldlen) == INTEGER_CST
1441 	       || TREE_CODE (srclen) == INTEGER_CST)
1442 	adj = fold_build2_loc (loc, MINUS_EXPR,
1443 			       TREE_TYPE (srclen), srclen,
1444 			       fold_convert_loc (loc, TREE_TYPE (srclen),
1445 						 oldlen));
1446       if (adj != NULL_TREE)
1447 	adjust_related_strinfos (loc, dsi, adj);
1448       else
1449 	dsi->prev = 0;
1450     }
1451   /* strcpy src may not overlap dst, so src doesn't need to be
1452      invalidated either.  */
1453   if (si != NULL)
1454     si->dont_invalidate = true;
1455 
1456   fn = NULL_TREE;
1457   zsi = NULL;
1458   switch (bcode)
1459     {
1460     case BUILT_IN_STRCPY:
1461     case BUILT_IN_STRCPY_CHKP:
1462       fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1463       if (lhs)
1464 	ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1465       break;
1466     case BUILT_IN_STRCPY_CHK:
1467     case BUILT_IN_STRCPY_CHK_CHKP:
1468       fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1469       if (lhs)
1470 	ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1471       break;
1472     case BUILT_IN_STPCPY:
1473     case BUILT_IN_STPCPY_CHKP:
1474       /* This would need adjustment of the lhs (subtract one),
1475 	 or detection that the trailing '\0' doesn't need to be
1476 	 written, if it will be immediately overwritten.
1477       fn = builtin_decl_explicit (BUILT_IN_MEMPCPY);  */
1478       if (lhs)
1479 	{
1480 	  dsi->endptr = lhs;
1481 	  zsi = zero_length_string (lhs, dsi);
1482 	}
1483       break;
1484     case BUILT_IN_STPCPY_CHK:
1485     case BUILT_IN_STPCPY_CHK_CHKP:
1486       /* This would need adjustment of the lhs (subtract one),
1487 	 or detection that the trailing '\0' doesn't need to be
1488 	 written, if it will be immediately overwritten.
1489       fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK);  */
1490       if (lhs)
1491 	{
1492 	  dsi->endptr = lhs;
1493 	  zsi = zero_length_string (lhs, dsi);
1494 	}
1495       break;
1496     default:
1497       gcc_unreachable ();
1498     }
1499   if (zsi != NULL)
1500     zsi->dont_invalidate = true;
1501 
1502   if (fn == NULL_TREE)
1503     return;
1504 
1505   args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1506   type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1507 
1508   len = fold_convert_loc (loc, type, unshare_expr (srclen));
1509   len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1510   len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1511 				  GSI_SAME_STMT);
1512   if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1513     {
1514       fprintf (dump_file, "Optimizing: ");
1515       print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1516     }
1517   if (with_bounds)
1518     {
1519       fn = chkp_maybe_create_clone (fn)->decl;
1520       if (gimple_call_num_args (stmt) == 4)
1521 	success = update_gimple_call (gsi, fn, 5, dst,
1522 				      gimple_call_arg (stmt, 1),
1523 				      src,
1524 				      gimple_call_arg (stmt, 3),
1525 				      len);
1526       else
1527 	success = update_gimple_call (gsi, fn, 6, dst,
1528 				      gimple_call_arg (stmt, 1),
1529 				      src,
1530 				      gimple_call_arg (stmt, 3),
1531 				      len,
1532 				      gimple_call_arg (stmt, 4));
1533     }
1534   else
1535     if (gimple_call_num_args (stmt) == 2)
1536       success = update_gimple_call (gsi, fn, 3, dst, src, len);
1537     else
1538       success = update_gimple_call (gsi, fn, 4, dst, src, len,
1539 				    gimple_call_arg (stmt, 2));
1540   if (success)
1541     {
1542       stmt = gsi_stmt (*gsi);
1543       gimple_call_set_with_bounds (stmt, with_bounds);
1544       update_stmt (stmt);
1545       if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1546 	{
1547 	  fprintf (dump_file, "into: ");
1548 	  print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1549 	}
1550       /* Allow adjust_last_stmt to decrease this memcpy's size.  */
1551       laststmt.stmt = stmt;
1552       laststmt.len = srclen;
1553       laststmt.stridx = dsi->idx;
1554     }
1555   else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1556     fprintf (dump_file, "not possible.\n");
1557 }
1558 
1559 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1560    If strlen of the second argument is known and length of the third argument
1561    is that plus one, strlen of the first argument is the same after this
1562    call.  */
1563 
1564 static void
1565 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1566 {
1567   int idx, didx;
1568   tree src, dst, len, lhs, oldlen, newlen;
1569   gimple *stmt = gsi_stmt (*gsi);
1570   strinfo *si, *dsi, *olddsi;
1571   bool with_bounds = gimple_call_with_bounds_p (stmt);
1572 
1573   len = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1574   src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1575   dst = gimple_call_arg (stmt, 0);
1576   idx = get_stridx (src);
1577   if (idx == 0)
1578     return;
1579 
1580   didx = get_stridx (dst);
1581   olddsi = NULL;
1582   if (didx > 0)
1583     olddsi = get_strinfo (didx);
1584   else if (didx < 0)
1585     return;
1586 
1587   if (olddsi != NULL
1588       && tree_fits_uhwi_p (len)
1589       && !integer_zerop (len))
1590     adjust_last_stmt (olddsi, stmt, false);
1591 
1592   if (idx > 0)
1593     {
1594       gimple *def_stmt;
1595 
1596       /* Handle memcpy (x, y, l) where l is strlen (y) + 1.  */
1597       si = get_strinfo (idx);
1598       if (si == NULL || si->length == NULL_TREE)
1599 	return;
1600       if (TREE_CODE (len) != SSA_NAME)
1601 	return;
1602       def_stmt = SSA_NAME_DEF_STMT (len);
1603       if (!is_gimple_assign (def_stmt)
1604 	  || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1605 	  || gimple_assign_rhs1 (def_stmt) != si->length
1606 	  || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1607 	return;
1608     }
1609   else
1610     {
1611       si = NULL;
1612       /* Handle memcpy (x, "abcd", 5) or
1613 	 memcpy (x, "abc\0uvw", 7).  */
1614       if (!tree_fits_uhwi_p (len)
1615 	  || tree_to_uhwi (len) <= (unsigned HOST_WIDE_INT) ~idx)
1616 	return;
1617     }
1618 
1619   if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1620     adjust_last_stmt (olddsi, stmt, false);
1621 
1622   if (didx == 0)
1623     {
1624       didx = new_stridx (dst);
1625       if (didx == 0)
1626 	return;
1627     }
1628   if (si != NULL)
1629     newlen = si->length;
1630   else
1631     newlen = build_int_cst (size_type_node, ~idx);
1632   oldlen = NULL_TREE;
1633   if (olddsi != NULL)
1634     {
1635       dsi = unshare_strinfo (olddsi);
1636       oldlen = olddsi->length;
1637       dsi->length = newlen;
1638       /* Break the chain, so adjust_related_strinfo on later pointers in
1639 	 the chain won't adjust this one anymore.  */
1640       dsi->next = 0;
1641       dsi->stmt = NULL;
1642       dsi->endptr = NULL_TREE;
1643     }
1644   else
1645     {
1646       dsi = new_strinfo (dst, didx, newlen);
1647       set_strinfo (didx, dsi);
1648       find_equal_ptrs (dst, didx);
1649     }
1650   dsi->writable = true;
1651   dsi->dont_invalidate = true;
1652   if (olddsi != NULL)
1653     {
1654       tree adj = NULL_TREE;
1655       location_t loc = gimple_location (stmt);
1656       if (oldlen == NULL_TREE)
1657 	;
1658       else if (integer_zerop (oldlen))
1659 	adj = dsi->length;
1660       else if (TREE_CODE (oldlen) == INTEGER_CST
1661 	       || TREE_CODE (dsi->length) == INTEGER_CST)
1662 	adj = fold_build2_loc (loc, MINUS_EXPR,
1663 			       TREE_TYPE (dsi->length), dsi->length,
1664 			       fold_convert_loc (loc, TREE_TYPE (dsi->length),
1665 						 oldlen));
1666       if (adj != NULL_TREE)
1667 	adjust_related_strinfos (loc, dsi, adj);
1668       else
1669 	dsi->prev = 0;
1670     }
1671   /* memcpy src may not overlap dst, so src doesn't need to be
1672      invalidated either.  */
1673   if (si != NULL)
1674     si->dont_invalidate = true;
1675 
1676   lhs = gimple_call_lhs (stmt);
1677   switch (bcode)
1678     {
1679     case BUILT_IN_MEMCPY:
1680     case BUILT_IN_MEMCPY_CHK:
1681     case BUILT_IN_MEMCPY_CHKP:
1682     case BUILT_IN_MEMCPY_CHK_CHKP:
1683       /* Allow adjust_last_stmt to decrease this memcpy's size.  */
1684       laststmt.stmt = stmt;
1685       laststmt.len = dsi->length;
1686       laststmt.stridx = dsi->idx;
1687       if (lhs)
1688 	ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1689       break;
1690     case BUILT_IN_MEMPCPY:
1691     case BUILT_IN_MEMPCPY_CHK:
1692     case BUILT_IN_MEMPCPY_CHKP:
1693     case BUILT_IN_MEMPCPY_CHK_CHKP:
1694       break;
1695     default:
1696       gcc_unreachable ();
1697     }
1698 }
1699 
1700 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1701    If strlen of the second argument is known, strlen of the first argument
1702    is increased by the length of the second argument.  Furthermore, attempt
1703    to convert it to memcpy/strcpy if the length of the first argument
1704    is known.  */
1705 
1706 static void
1707 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1708 {
1709   int idx, didx;
1710   tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1711   bool success;
1712   gimple *stmt = gsi_stmt (*gsi);
1713   strinfo *si, *dsi;
1714   location_t loc;
1715   bool with_bounds = gimple_call_with_bounds_p (stmt);
1716 
1717   src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1718   dst = gimple_call_arg (stmt, 0);
1719   lhs = gimple_call_lhs (stmt);
1720 
1721   didx = get_stridx (dst);
1722   if (didx < 0)
1723     return;
1724 
1725   dsi = NULL;
1726   if (didx > 0)
1727     dsi = get_strinfo (didx);
1728   if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1729     {
1730       /* strcat (p, q) can be transformed into
1731 	 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1732 	 with length endptr - p if we need to compute the length
1733 	 later on.  Don't do this transformation if we don't need
1734 	 it.  */
1735       if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1736 	{
1737 	  if (didx == 0)
1738 	    {
1739 	      didx = new_stridx (dst);
1740 	      if (didx == 0)
1741 		return;
1742 	    }
1743 	  if (dsi == NULL)
1744 	    {
1745 	      dsi = new_strinfo (dst, didx, NULL_TREE);
1746 	      set_strinfo (didx, dsi);
1747 	      find_equal_ptrs (dst, didx);
1748 	    }
1749 	  else
1750 	    {
1751 	      dsi = unshare_strinfo (dsi);
1752 	      dsi->length = NULL_TREE;
1753 	      dsi->next = 0;
1754 	      dsi->endptr = NULL_TREE;
1755 	    }
1756 	  dsi->writable = true;
1757 	  dsi->stmt = stmt;
1758 	  dsi->dont_invalidate = true;
1759 	}
1760       return;
1761     }
1762 
1763   srclen = NULL_TREE;
1764   si = NULL;
1765   idx = get_stridx (src);
1766   if (idx < 0)
1767     srclen = build_int_cst (size_type_node, ~idx);
1768   else if (idx > 0)
1769     {
1770       si = get_strinfo (idx);
1771       if (si != NULL)
1772 	srclen = get_string_length (si);
1773     }
1774 
1775   loc = gimple_location (stmt);
1776   dstlen = dsi->length;
1777   endptr = dsi->endptr;
1778 
1779   dsi = unshare_strinfo (dsi);
1780   dsi->endptr = NULL_TREE;
1781   dsi->stmt = NULL;
1782   dsi->writable = true;
1783 
1784   if (srclen != NULL_TREE)
1785     {
1786       dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1787 				     dsi->length, srclen);
1788       adjust_related_strinfos (loc, dsi, srclen);
1789       dsi->dont_invalidate = true;
1790     }
1791   else
1792     {
1793       dsi->length = NULL;
1794       if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1795 	dsi->dont_invalidate = true;
1796     }
1797 
1798   if (si != NULL)
1799     /* strcat src may not overlap dst, so src doesn't need to be
1800        invalidated either.  */
1801     si->dont_invalidate = true;
1802 
1803   /* For now.  Could remove the lhs from the call and add
1804      lhs = dst; afterwards.  */
1805   if (lhs)
1806     return;
1807 
1808   fn = NULL_TREE;
1809   objsz = NULL_TREE;
1810   switch (bcode)
1811     {
1812     case BUILT_IN_STRCAT:
1813     case BUILT_IN_STRCAT_CHKP:
1814       if (srclen != NULL_TREE)
1815 	fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1816       else
1817 	fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1818       break;
1819     case BUILT_IN_STRCAT_CHK:
1820     case BUILT_IN_STRCAT_CHK_CHKP:
1821       if (srclen != NULL_TREE)
1822 	fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1823       else
1824 	fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1825       objsz = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1826       break;
1827     default:
1828       gcc_unreachable ();
1829     }
1830 
1831   if (fn == NULL_TREE)
1832     return;
1833 
1834   len = NULL_TREE;
1835   if (srclen != NULL_TREE)
1836     {
1837       args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1838       type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1839 
1840       len = fold_convert_loc (loc, type, unshare_expr (srclen));
1841       len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1842 			     build_int_cst (type, 1));
1843       len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1844 				      GSI_SAME_STMT);
1845     }
1846   if (endptr)
1847     dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1848   else
1849     dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1850 			   TREE_TYPE (dst), unshare_expr (dst),
1851 			   fold_convert_loc (loc, sizetype,
1852 					     unshare_expr (dstlen)));
1853   dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1854 				  GSI_SAME_STMT);
1855   if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1856     {
1857       fprintf (dump_file, "Optimizing: ");
1858       print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1859     }
1860   if (with_bounds)
1861     {
1862       fn = chkp_maybe_create_clone (fn)->decl;
1863       if (srclen != NULL_TREE)
1864 	success = update_gimple_call (gsi, fn, 5 + (objsz != NULL_TREE),
1865 				      dst,
1866 				      gimple_call_arg (stmt, 1),
1867 				      src,
1868 				      gimple_call_arg (stmt, 3),
1869 				      len, objsz);
1870       else
1871 	success = update_gimple_call (gsi, fn, 4 + (objsz != NULL_TREE),
1872 				      dst,
1873 				      gimple_call_arg (stmt, 1),
1874 				      src,
1875 				      gimple_call_arg (stmt, 3),
1876 				      objsz);
1877     }
1878   else
1879     if (srclen != NULL_TREE)
1880       success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1881 				    dst, src, len, objsz);
1882     else
1883       success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1884 				    dst, src, objsz);
1885   if (success)
1886     {
1887       stmt = gsi_stmt (*gsi);
1888       gimple_call_set_with_bounds (stmt, with_bounds);
1889       update_stmt (stmt);
1890       if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1891 	{
1892 	  fprintf (dump_file, "into: ");
1893 	  print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1894 	}
1895       /* If srclen == NULL, note that current string length can be
1896 	 computed by transforming this strcpy into stpcpy.  */
1897       if (srclen == NULL_TREE && dsi->dont_invalidate)
1898 	dsi->stmt = stmt;
1899       adjust_last_stmt (dsi, stmt, true);
1900       if (srclen != NULL_TREE)
1901 	{
1902 	  laststmt.stmt = stmt;
1903 	  laststmt.len = srclen;
1904 	  laststmt.stridx = dsi->idx;
1905 	}
1906     }
1907   else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1908     fprintf (dump_file, "not possible.\n");
1909 }
1910 
1911 /* Handle a call to malloc or calloc.  */
1912 
1913 static void
1914 handle_builtin_malloc (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1915 {
1916   gimple *stmt = gsi_stmt (*gsi);
1917   tree lhs = gimple_call_lhs (stmt);
1918   if (lhs == NULL_TREE)
1919     return;
1920 
1921   gcc_assert (get_stridx (lhs) == 0);
1922   int idx = new_stridx (lhs);
1923   tree length = NULL_TREE;
1924   if (bcode == BUILT_IN_CALLOC)
1925     length = build_int_cst (size_type_node, 0);
1926   strinfo *si = new_strinfo (lhs, idx, length);
1927   if (bcode == BUILT_IN_CALLOC)
1928     si->endptr = lhs;
1929   set_strinfo (idx, si);
1930   si->writable = true;
1931   si->stmt = stmt;
1932   si->dont_invalidate = true;
1933 }
1934 
1935 /* Handle a call to memset.
1936    After a call to calloc, memset(,0,) is unnecessary.
1937    memset(malloc(n),0,n) is calloc(n,1).  */
1938 
1939 static bool
1940 handle_builtin_memset (gimple_stmt_iterator *gsi)
1941 {
1942   gimple *stmt2 = gsi_stmt (*gsi);
1943   if (!integer_zerop (gimple_call_arg (stmt2, 1)))
1944     return true;
1945   tree ptr = gimple_call_arg (stmt2, 0);
1946   int idx1 = get_stridx (ptr);
1947   if (idx1 <= 0)
1948     return true;
1949   strinfo *si1 = get_strinfo (idx1);
1950   if (!si1)
1951     return true;
1952   gimple *stmt1 = si1->stmt;
1953   if (!stmt1 || !is_gimple_call (stmt1))
1954     return true;
1955   tree callee1 = gimple_call_fndecl (stmt1);
1956   if (!valid_builtin_call (stmt1))
1957     return true;
1958   enum built_in_function code1 = DECL_FUNCTION_CODE (callee1);
1959   tree size = gimple_call_arg (stmt2, 2);
1960   if (code1 == BUILT_IN_CALLOC)
1961     /* Not touching stmt1 */ ;
1962   else if (code1 == BUILT_IN_MALLOC
1963 	   && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0))
1964     {
1965       gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1);
1966       update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2,
1967 			  size, build_one_cst (size_type_node));
1968       si1->length = build_int_cst (size_type_node, 0);
1969       si1->stmt = gsi_stmt (gsi1);
1970     }
1971   else
1972     return true;
1973   tree lhs = gimple_call_lhs (stmt2);
1974   unlink_stmt_vdef (stmt2);
1975   if (lhs)
1976     {
1977       gimple *assign = gimple_build_assign (lhs, ptr);
1978       gsi_replace (gsi, assign, false);
1979     }
1980   else
1981     {
1982       gsi_remove (gsi, true);
1983       release_defs (stmt2);
1984     }
1985 
1986   return false;
1987 }
1988 
1989 /* Handle a call to memcmp.  We try to handle small comparisons by
1990    converting them to load and compare, and replacing the call to memcmp
1991    with a __builtin_memcmp_eq call where possible.  */
1992 
1993 static bool
1994 handle_builtin_memcmp (gimple_stmt_iterator *gsi)
1995 {
1996   gcall *stmt2 = as_a <gcall *> (gsi_stmt (*gsi));
1997   tree res = gimple_call_lhs (stmt2);
1998   tree arg1 = gimple_call_arg (stmt2, 0);
1999   tree arg2 = gimple_call_arg (stmt2, 1);
2000   tree len = gimple_call_arg (stmt2, 2);
2001   unsigned HOST_WIDE_INT leni;
2002   use_operand_p use_p;
2003   imm_use_iterator iter;
2004 
2005   if (!res)
2006     return true;
2007 
2008   FOR_EACH_IMM_USE_FAST (use_p, iter, res)
2009     {
2010       gimple *ustmt = USE_STMT (use_p);
2011 
2012       if (is_gimple_debug (ustmt))
2013 	continue;
2014       if (gimple_code (ustmt) == GIMPLE_ASSIGN)
2015 	{
2016 	  gassign *asgn = as_a <gassign *> (ustmt);
2017 	  tree_code code = gimple_assign_rhs_code (asgn);
2018 	  if ((code != EQ_EXPR && code != NE_EXPR)
2019 	      || !integer_zerop (gimple_assign_rhs2 (asgn)))
2020 	    return true;
2021 	}
2022       else if (gimple_code (ustmt) == GIMPLE_COND)
2023 	{
2024 	  tree_code code = gimple_cond_code (ustmt);
2025 	  if ((code != EQ_EXPR && code != NE_EXPR)
2026 	      || !integer_zerop (gimple_cond_rhs (ustmt)))
2027 	    return true;
2028 	}
2029       else
2030 	return true;
2031     }
2032 
2033   if (tree_fits_uhwi_p (len)
2034       && (leni = tree_to_uhwi (len)) <= GET_MODE_SIZE (word_mode)
2035       && pow2p_hwi (leni))
2036     {
2037       leni *= CHAR_TYPE_SIZE;
2038       unsigned align1 = get_pointer_alignment (arg1);
2039       unsigned align2 = get_pointer_alignment (arg2);
2040       unsigned align = MIN (align1, align2);
2041       machine_mode mode = mode_for_size (leni, MODE_INT, 1);
2042       if (mode != BLKmode
2043 	  && (align >= leni || !SLOW_UNALIGNED_ACCESS (mode, align)))
2044 	{
2045 	  location_t loc = gimple_location (stmt2);
2046 	  tree type, off;
2047 	  type = build_nonstandard_integer_type (leni, 1);
2048 	  gcc_assert (GET_MODE_BITSIZE (TYPE_MODE (type)) == leni);
2049 	  tree ptrtype = build_pointer_type_for_mode (char_type_node,
2050 						      ptr_mode, true);
2051 	  off = build_int_cst (ptrtype, 0);
2052 	  arg1 = build2_loc (loc, MEM_REF, type, arg1, off);
2053 	  arg2 = build2_loc (loc, MEM_REF, type, arg2, off);
2054 	  tree tem1 = fold_const_aggregate_ref (arg1);
2055 	  if (tem1)
2056 	    arg1 = tem1;
2057 	  tree tem2 = fold_const_aggregate_ref (arg2);
2058 	  if (tem2)
2059 	    arg2 = tem2;
2060 	  res = fold_convert_loc (loc, TREE_TYPE (res),
2061 				  fold_build2_loc (loc, NE_EXPR,
2062 						   boolean_type_node,
2063 						   arg1, arg2));
2064 	  gimplify_and_update_call_from_tree (gsi, res);
2065 	  return false;
2066 	}
2067     }
2068 
2069   gimple_call_set_fndecl (stmt2, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ));
2070   return false;
2071 }
2072 
2073 /* Handle a POINTER_PLUS_EXPR statement.
2074    For p = "abcd" + 2; compute associated length, or if
2075    p = q + off is pointing to a '\0' character of a string, call
2076    zero_length_string on it.  */
2077 
2078 static void
2079 handle_pointer_plus (gimple_stmt_iterator *gsi)
2080 {
2081   gimple *stmt = gsi_stmt (*gsi);
2082   tree lhs = gimple_assign_lhs (stmt), off;
2083   int idx = get_stridx (gimple_assign_rhs1 (stmt));
2084   strinfo *si, *zsi;
2085 
2086   if (idx == 0)
2087     return;
2088 
2089   if (idx < 0)
2090     {
2091       tree off = gimple_assign_rhs2 (stmt);
2092       if (tree_fits_uhwi_p (off)
2093 	  && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx)
2094 	ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
2095 	    = ~(~idx - (int) tree_to_uhwi (off));
2096       return;
2097     }
2098 
2099   si = get_strinfo (idx);
2100   if (si == NULL || si->length == NULL_TREE)
2101     return;
2102 
2103   off = gimple_assign_rhs2 (stmt);
2104   zsi = NULL;
2105   if (operand_equal_p (si->length, off, 0))
2106     zsi = zero_length_string (lhs, si);
2107   else if (TREE_CODE (off) == SSA_NAME)
2108     {
2109       gimple *def_stmt = SSA_NAME_DEF_STMT (off);
2110       if (gimple_assign_single_p (def_stmt)
2111 	  && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
2112 	zsi = zero_length_string (lhs, si);
2113     }
2114   if (zsi != NULL
2115       && si->endptr != NULL_TREE
2116       && si->endptr != lhs
2117       && TREE_CODE (si->endptr) == SSA_NAME)
2118     {
2119       enum tree_code rhs_code
2120 	= useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
2121 	  ? SSA_NAME : NOP_EXPR;
2122       gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr);
2123       gcc_assert (gsi_stmt (*gsi) == stmt);
2124       update_stmt (stmt);
2125     }
2126 }
2127 
2128 /* Handle a single character store.  */
2129 
2130 static bool
2131 handle_char_store (gimple_stmt_iterator *gsi)
2132 {
2133   int idx = -1;
2134   strinfo *si = NULL;
2135   gimple *stmt = gsi_stmt (*gsi);
2136   tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
2137 
2138   if (TREE_CODE (lhs) == MEM_REF
2139       && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
2140     {
2141       if (integer_zerop (TREE_OPERAND (lhs, 1)))
2142 	{
2143 	  ssaname = TREE_OPERAND (lhs, 0);
2144 	  idx = get_stridx (ssaname);
2145 	}
2146     }
2147   else
2148     idx = get_addr_stridx (lhs, NULL_TREE);
2149 
2150   if (idx > 0)
2151     {
2152       si = get_strinfo (idx);
2153       if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
2154 	{
2155 	  if (initializer_zerop (gimple_assign_rhs1 (stmt)))
2156 	    {
2157 	      /* When storing '\0', the store can be removed
2158 		 if we know it has been stored in the current function.  */
2159 	      if (!stmt_could_throw_p (stmt) && si->writable)
2160 		{
2161 		  unlink_stmt_vdef (stmt);
2162 		  release_defs (stmt);
2163 		  gsi_remove (gsi, true);
2164 		  return false;
2165 		}
2166 	      else
2167 		{
2168 		  si->writable = true;
2169 		  gsi_next (gsi);
2170 		  return false;
2171 		}
2172 	    }
2173 	  else
2174 	    /* Otherwise this statement overwrites the '\0' with
2175 	       something, if the previous stmt was a memcpy,
2176 	       its length may be decreased.  */
2177 	    adjust_last_stmt (si, stmt, false);
2178 	}
2179       else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt)))
2180 	{
2181 	  si = unshare_strinfo (si);
2182 	  si->length = build_int_cst (size_type_node, 0);
2183 	  si->endptr = NULL;
2184 	  si->prev = 0;
2185 	  si->next = 0;
2186 	  si->stmt = NULL;
2187 	  si->first = 0;
2188 	  si->writable = true;
2189 	  if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
2190 	    si->endptr = ssaname;
2191 	  si->dont_invalidate = true;
2192 	}
2193       /* If si->length is non-zero constant, we aren't overwriting '\0',
2194 	 and if we aren't storing '\0', we know that the length of the
2195 	 string and any other zero terminated string in memory remains
2196 	 the same.  In that case we move to the next gimple statement and
2197 	 return to signal the caller that it shouldn't invalidate anything.
2198 
2199 	 This is benefical for cases like:
2200 
2201 	 char p[20];
2202 	 void foo (char *q)
2203 	 {
2204 	   strcpy (p, "foobar");
2205 	   size_t len = strlen (p);        // This can be optimized into 6
2206 	   size_t len2 = strlen (q);        // This has to be computed
2207 	   p[0] = 'X';
2208 	   size_t len3 = strlen (p);        // This can be optimized into 6
2209 	   size_t len4 = strlen (q);        // This can be optimized into len2
2210 	   bar (len, len2, len3, len4);
2211         }
2212 	*/
2213       else if (si != NULL && si->length != NULL_TREE
2214 	       && TREE_CODE (si->length) == INTEGER_CST
2215 	       && integer_nonzerop (gimple_assign_rhs1 (stmt)))
2216 	{
2217 	  gsi_next (gsi);
2218 	  return false;
2219 	}
2220     }
2221   else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
2222     {
2223       if (ssaname)
2224 	{
2225 	  si = zero_length_string (ssaname, NULL);
2226 	  if (si != NULL)
2227 	    si->dont_invalidate = true;
2228 	}
2229       else
2230 	{
2231 	  int idx = new_addr_stridx (lhs);
2232 	  if (idx != 0)
2233 	    {
2234 	      si = new_strinfo (build_fold_addr_expr (lhs), idx,
2235 				build_int_cst (size_type_node, 0));
2236 	      set_strinfo (idx, si);
2237 	      si->dont_invalidate = true;
2238 	    }
2239 	}
2240       if (si != NULL)
2241 	si->writable = true;
2242     }
2243   else if (idx == 0
2244 	   && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
2245 	   && ssaname == NULL_TREE
2246 	   && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
2247     {
2248       size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
2249       HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
2250       if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
2251 	{
2252 	  int idx = new_addr_stridx (lhs);
2253 	  if (idx != 0)
2254 	    {
2255 	      si = new_strinfo (build_fold_addr_expr (lhs), idx,
2256 				build_int_cst (size_type_node, l));
2257 	      set_strinfo (idx, si);
2258 	      si->dont_invalidate = true;
2259 	    }
2260 	}
2261     }
2262 
2263   if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
2264     {
2265       /* Allow adjust_last_stmt to remove it if the stored '\0'
2266 	 is immediately overwritten.  */
2267       laststmt.stmt = stmt;
2268       laststmt.len = build_int_cst (size_type_node, 1);
2269       laststmt.stridx = si->idx;
2270     }
2271   return true;
2272 }
2273 
2274 /* Try to fold strstr (s, t) eq/ne s to strncmp (s, t, strlen (t)) eq/ne 0.  */
2275 
2276 static void
2277 fold_strstr_to_strncmp (tree rhs1, tree rhs2, gimple *stmt)
2278 {
2279   if (TREE_CODE (rhs1) != SSA_NAME
2280       || TREE_CODE (rhs2) != SSA_NAME)
2281     return;
2282 
2283   gimple *call_stmt = NULL;
2284   for (int pass = 0; pass < 2; pass++)
2285     {
2286       gimple *g = SSA_NAME_DEF_STMT (rhs1);
2287       if (gimple_call_builtin_p (g, BUILT_IN_STRSTR)
2288 	  && has_single_use (rhs1)
2289 	  && gimple_call_arg (g, 0) == rhs2)
2290 	{
2291 	  call_stmt = g;
2292 	  break;
2293 	}
2294       std::swap (rhs1, rhs2);
2295     }
2296 
2297   if (call_stmt)
2298     {
2299       tree arg0 = gimple_call_arg (call_stmt, 0);
2300 
2301       if (arg0 == rhs2)
2302 	{
2303 	  tree arg1 = gimple_call_arg (call_stmt, 1);
2304 	  tree arg1_len = NULL_TREE;
2305 	  int idx = get_stridx (arg1);
2306 
2307 	  if (idx)
2308 	    {
2309 	      if (idx < 0)
2310 		arg1_len = build_int_cst (size_type_node, ~idx);
2311 	      else
2312 		{
2313 		  strinfo *si = get_strinfo (idx);
2314 		  if (si)
2315 		    arg1_len = get_string_length (si);
2316 		}
2317 	    }
2318 
2319 	  if (arg1_len != NULL_TREE)
2320 	    {
2321 	      gimple_stmt_iterator gsi = gsi_for_stmt (call_stmt);
2322 	      tree strncmp_decl = builtin_decl_explicit (BUILT_IN_STRNCMP);
2323 
2324 	      if (!is_gimple_val (arg1_len))
2325 		{
2326 		  tree arg1_len_tmp = make_ssa_name (TREE_TYPE (arg1_len));
2327 		  gassign *arg1_stmt = gimple_build_assign (arg1_len_tmp,
2328 							    arg1_len);
2329 		  gsi_insert_before (&gsi, arg1_stmt, GSI_SAME_STMT);
2330 		  arg1_len = arg1_len_tmp;
2331 		}
2332 
2333 	      gcall *strncmp_call = gimple_build_call (strncmp_decl, 3,
2334 						      arg0, arg1, arg1_len);
2335 	      tree strncmp_lhs = make_ssa_name (integer_type_node);
2336 	      gimple_set_vuse (strncmp_call, gimple_vuse (call_stmt));
2337 	      gimple_call_set_lhs (strncmp_call, strncmp_lhs);
2338 	      gsi_remove (&gsi, true);
2339 	      gsi_insert_before (&gsi, strncmp_call, GSI_SAME_STMT);
2340 	      tree zero = build_zero_cst (TREE_TYPE (strncmp_lhs));
2341 
2342 	      if (is_gimple_assign (stmt))
2343 		{
2344 		  if (gimple_assign_rhs_code (stmt) == COND_EXPR)
2345 		    {
2346 		      tree cond = gimple_assign_rhs1 (stmt);
2347 		      TREE_OPERAND (cond, 0) = strncmp_lhs;
2348 		      TREE_OPERAND (cond, 1) = zero;
2349 		    }
2350 		  else
2351 		    {
2352 		      gimple_assign_set_rhs1 (stmt, strncmp_lhs);
2353 		      gimple_assign_set_rhs2 (stmt, zero);
2354 		    }
2355 		}
2356 	      else
2357 		{
2358 		  gcond *cond = as_a<gcond *> (stmt);
2359 		  gimple_cond_set_lhs (cond, strncmp_lhs);
2360 		  gimple_cond_set_rhs (cond, zero);
2361 		}
2362 	      update_stmt (stmt);
2363 	    }
2364 	}
2365     }
2366 }
2367 
2368 /* Attempt to optimize a single statement at *GSI using string length
2369    knowledge.  */
2370 
2371 static bool
2372 strlen_optimize_stmt (gimple_stmt_iterator *gsi)
2373 {
2374   gimple *stmt = gsi_stmt (*gsi);
2375 
2376   if (is_gimple_call (stmt))
2377     {
2378       tree callee = gimple_call_fndecl (stmt);
2379       if (valid_builtin_call (stmt))
2380 	switch (DECL_FUNCTION_CODE (callee))
2381 	  {
2382 	  case BUILT_IN_STRLEN:
2383 	  case BUILT_IN_STRLEN_CHKP:
2384 	    handle_builtin_strlen (gsi);
2385 	    break;
2386 	  case BUILT_IN_STRCHR:
2387 	  case BUILT_IN_STRCHR_CHKP:
2388 	    handle_builtin_strchr (gsi);
2389 	    break;
2390 	  case BUILT_IN_STRCPY:
2391 	  case BUILT_IN_STRCPY_CHK:
2392 	  case BUILT_IN_STPCPY:
2393 	  case BUILT_IN_STPCPY_CHK:
2394 	  case BUILT_IN_STRCPY_CHKP:
2395 	  case BUILT_IN_STRCPY_CHK_CHKP:
2396 	  case BUILT_IN_STPCPY_CHKP:
2397 	  case BUILT_IN_STPCPY_CHK_CHKP:
2398 	    handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
2399 	    break;
2400 	  case BUILT_IN_MEMCPY:
2401 	  case BUILT_IN_MEMCPY_CHK:
2402 	  case BUILT_IN_MEMPCPY:
2403 	  case BUILT_IN_MEMPCPY_CHK:
2404 	  case BUILT_IN_MEMCPY_CHKP:
2405 	  case BUILT_IN_MEMCPY_CHK_CHKP:
2406 	  case BUILT_IN_MEMPCPY_CHKP:
2407 	  case BUILT_IN_MEMPCPY_CHK_CHKP:
2408 	    handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
2409 	    break;
2410 	  case BUILT_IN_STRCAT:
2411 	  case BUILT_IN_STRCAT_CHK:
2412 	  case BUILT_IN_STRCAT_CHKP:
2413 	  case BUILT_IN_STRCAT_CHK_CHKP:
2414 	    handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
2415 	    break;
2416 	  case BUILT_IN_MALLOC:
2417 	  case BUILT_IN_CALLOC:
2418 	    handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi);
2419 	    break;
2420 	  case BUILT_IN_MEMSET:
2421 	    if (!handle_builtin_memset (gsi))
2422 	      return false;
2423 	    break;
2424 	  case BUILT_IN_MEMCMP:
2425 	    if (!handle_builtin_memcmp (gsi))
2426 	      return false;
2427 	    break;
2428 	  default:
2429 	    break;
2430 	  }
2431     }
2432   else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt))
2433     {
2434       tree lhs = gimple_assign_lhs (stmt);
2435 
2436       if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
2437 	{
2438 	  if (gimple_assign_single_p (stmt)
2439 	      || (gimple_assign_cast_p (stmt)
2440 		  && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
2441 	    {
2442 	      int idx = get_stridx (gimple_assign_rhs1 (stmt));
2443 	      ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
2444 	    }
2445 	  else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
2446 	    handle_pointer_plus (gsi);
2447 	}
2448     else if (TREE_CODE (lhs) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
2449       {
2450 	enum tree_code code = gimple_assign_rhs_code (stmt);
2451 	if (code == COND_EXPR)
2452 	  {
2453 	    tree cond = gimple_assign_rhs1 (stmt);
2454 	    enum tree_code cond_code = TREE_CODE (cond);
2455 
2456 	    if (cond_code == EQ_EXPR || cond_code == NE_EXPR)
2457 	      fold_strstr_to_strncmp (TREE_OPERAND (cond, 0),
2458 				      TREE_OPERAND (cond, 1), stmt);
2459 	  }
2460 	else if (code == EQ_EXPR || code == NE_EXPR)
2461 	  fold_strstr_to_strncmp (gimple_assign_rhs1 (stmt),
2462 				  gimple_assign_rhs2 (stmt), stmt);
2463       }
2464     else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
2465 	{
2466 	  tree type = TREE_TYPE (lhs);
2467 	  if (TREE_CODE (type) == ARRAY_TYPE)
2468 	    type = TREE_TYPE (type);
2469 	  if (TREE_CODE (type) == INTEGER_TYPE
2470 	      && TYPE_MODE (type) == TYPE_MODE (char_type_node)
2471 	      && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
2472 	    {
2473 	      if (! handle_char_store (gsi))
2474 		return false;
2475 	    }
2476 	}
2477     }
2478   else if (gcond *cond = dyn_cast<gcond *> (stmt))
2479     {
2480       enum tree_code code = gimple_cond_code (cond);
2481       if (code == EQ_EXPR || code == NE_EXPR)
2482 	fold_strstr_to_strncmp (gimple_cond_lhs (stmt),
2483 				gimple_cond_rhs (stmt), stmt);
2484     }
2485 
2486   if (gimple_vdef (stmt))
2487     maybe_invalidate (stmt);
2488   return true;
2489 }
2490 
2491 /* Recursively call maybe_invalidate on stmts that might be executed
2492    in between dombb and current bb and that contain a vdef.  Stop when
2493    *count stmts are inspected, or if the whole strinfo vector has
2494    been invalidated.  */
2495 
2496 static void
2497 do_invalidate (basic_block dombb, gimple *phi, bitmap visited, int *count)
2498 {
2499   unsigned int i, n = gimple_phi_num_args (phi);
2500 
2501   for (i = 0; i < n; i++)
2502     {
2503       tree vuse = gimple_phi_arg_def (phi, i);
2504       gimple *stmt = SSA_NAME_DEF_STMT (vuse);
2505       basic_block bb = gimple_bb (stmt);
2506       if (bb == NULL
2507 	  || bb == dombb
2508 	  || !bitmap_set_bit (visited, bb->index)
2509 	  || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2510 	continue;
2511       while (1)
2512 	{
2513 	  if (gimple_code (stmt) == GIMPLE_PHI)
2514 	    {
2515 	      do_invalidate (dombb, stmt, visited, count);
2516 	      if (*count == 0)
2517 		return;
2518 	      break;
2519 	    }
2520 	  if (--*count == 0)
2521 	    return;
2522 	  if (!maybe_invalidate (stmt))
2523 	    {
2524 	      *count = 0;
2525 	      return;
2526 	    }
2527 	  vuse = gimple_vuse (stmt);
2528 	  stmt = SSA_NAME_DEF_STMT (vuse);
2529 	  if (gimple_bb (stmt) != bb)
2530 	    {
2531 	      bb = gimple_bb (stmt);
2532 	      if (bb == NULL
2533 		  || bb == dombb
2534 		  || !bitmap_set_bit (visited, bb->index)
2535 		  || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2536 		break;
2537 	    }
2538 	}
2539     }
2540 }
2541 
2542 class strlen_dom_walker : public dom_walker
2543 {
2544 public:
2545   strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
2546 
2547   virtual edge before_dom_children (basic_block);
2548   virtual void after_dom_children (basic_block);
2549 };
2550 
2551 /* Callback for walk_dominator_tree.  Attempt to optimize various
2552    string ops by remembering string lengths pointed by pointer SSA_NAMEs.  */
2553 
2554 edge
2555 strlen_dom_walker::before_dom_children (basic_block bb)
2556 {
2557   basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
2558 
2559   if (dombb == NULL)
2560     stridx_to_strinfo = NULL;
2561   else
2562     {
2563       stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) dombb->aux);
2564       if (stridx_to_strinfo)
2565 	{
2566 	  for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2567 	       gsi_next (&gsi))
2568 	    {
2569 	      gphi *phi = gsi.phi ();
2570 	      if (virtual_operand_p (gimple_phi_result (phi)))
2571 		{
2572 		  bitmap visited = BITMAP_ALLOC (NULL);
2573 		  int count_vdef = 100;
2574 		  do_invalidate (dombb, phi, visited, &count_vdef);
2575 		  BITMAP_FREE (visited);
2576 		  if (count_vdef == 0)
2577 		    {
2578 		      /* If there were too many vdefs in between immediate
2579 			 dominator and current bb, invalidate everything.
2580 			 If stridx_to_strinfo has been unshared, we need
2581 			 to free it, otherwise just set it to NULL.  */
2582 		      if (!strinfo_shared ())
2583 			{
2584 			  unsigned int i;
2585 			  strinfo *si;
2586 
2587 			  for (i = 1;
2588 			       vec_safe_iterate (stridx_to_strinfo, i, &si);
2589 			       ++i)
2590 			    {
2591 			      free_strinfo (si);
2592 			      (*stridx_to_strinfo)[i] = NULL;
2593 			    }
2594 			}
2595 		      else
2596 			stridx_to_strinfo = NULL;
2597 		    }
2598 		  break;
2599 		}
2600 	    }
2601 	}
2602     }
2603 
2604   /* If all PHI arguments have the same string index, the PHI result
2605      has it as well.  */
2606   for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2607        gsi_next (&gsi))
2608     {
2609       gphi *phi = gsi.phi ();
2610       tree result = gimple_phi_result (phi);
2611       if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
2612 	{
2613 	  int idx = get_stridx (gimple_phi_arg_def (phi, 0));
2614 	  if (idx != 0)
2615 	    {
2616 	      unsigned int i, n = gimple_phi_num_args (phi);
2617 	      for (i = 1; i < n; i++)
2618 		if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
2619 		  break;
2620 	      if (i == n)
2621 		ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
2622 	    }
2623 	}
2624     }
2625 
2626   /* Attempt to optimize individual statements.  */
2627   for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2628     if (strlen_optimize_stmt (&gsi))
2629       gsi_next (&gsi);
2630 
2631   bb->aux = stridx_to_strinfo;
2632   if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
2633     (*stridx_to_strinfo)[0] = (strinfo *) bb;
2634   return NULL;
2635 }
2636 
2637 /* Callback for walk_dominator_tree.  Free strinfo vector if it is
2638    owned by the current bb, clear bb->aux.  */
2639 
2640 void
2641 strlen_dom_walker::after_dom_children (basic_block bb)
2642 {
2643   if (bb->aux)
2644     {
2645       stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) bb->aux);
2646       if (vec_safe_length (stridx_to_strinfo)
2647 	  && (*stridx_to_strinfo)[0] == (strinfo *) bb)
2648 	{
2649 	  unsigned int i;
2650 	  strinfo *si;
2651 
2652 	  for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
2653 	    free_strinfo (si);
2654 	  vec_free (stridx_to_strinfo);
2655 	}
2656       bb->aux = NULL;
2657     }
2658 }
2659 
2660 /* Main entry point.  */
2661 
2662 namespace {
2663 
2664 const pass_data pass_data_strlen =
2665 {
2666   GIMPLE_PASS, /* type */
2667   "strlen", /* name */
2668   OPTGROUP_NONE, /* optinfo_flags */
2669   TV_TREE_STRLEN, /* tv_id */
2670   ( PROP_cfg | PROP_ssa ), /* properties_required */
2671   0, /* properties_provided */
2672   0, /* properties_destroyed */
2673   0, /* todo_flags_start */
2674   0, /* todo_flags_finish */
2675 };
2676 
2677 class pass_strlen : public gimple_opt_pass
2678 {
2679 public:
2680   pass_strlen (gcc::context *ctxt)
2681     : gimple_opt_pass (pass_data_strlen, ctxt)
2682   {}
2683 
2684   /* opt_pass methods: */
2685   virtual bool gate (function *) { return flag_optimize_strlen != 0; }
2686   virtual unsigned int execute (function *);
2687 
2688 }; // class pass_strlen
2689 
2690 unsigned int
2691 pass_strlen::execute (function *fun)
2692 {
2693   ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
2694   max_stridx = 1;
2695 
2696   calculate_dominance_info (CDI_DOMINATORS);
2697 
2698   /* String length optimization is implemented as a walk of the dominator
2699      tree and a forward walk of statements within each block.  */
2700   strlen_dom_walker (CDI_DOMINATORS).walk (fun->cfg->x_entry_block_ptr);
2701 
2702   ssa_ver_to_stridx.release ();
2703   strinfo_pool.release ();
2704   if (decl_to_stridxlist_htab)
2705     {
2706       obstack_free (&stridx_obstack, NULL);
2707       delete decl_to_stridxlist_htab;
2708       decl_to_stridxlist_htab = NULL;
2709     }
2710   laststmt.stmt = NULL;
2711   laststmt.len = NULL_TREE;
2712   laststmt.stridx = 0;
2713 
2714   return 0;
2715 }
2716 
2717 } // anon namespace
2718 
2719 gimple_opt_pass *
2720 make_pass_strlen (gcc::context *ctxt)
2721 {
2722   return new pass_strlen (ctxt);
2723 }
2724