xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/tree-ssa-strlen.c (revision e6c7e151de239c49d2e38720a061ed9d1fa99309)
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   switch (DECL_FUNCTION_CODE (callee))
940     {
941     case BUILT_IN_MEMCMP:
942     case BUILT_IN_MEMCMP_EQ:
943     case BUILT_IN_STRCHR:
944     case BUILT_IN_STRCHR_CHKP:
945     case BUILT_IN_STRLEN:
946     case BUILT_IN_STRLEN_CHKP:
947       /* The above functions should be pure.  Punt if they aren't.  */
948       if (gimple_vdef (stmt) || gimple_vuse (stmt) == NULL_TREE)
949 	return false;
950       break;
951 
952     case BUILT_IN_CALLOC:
953     case BUILT_IN_MALLOC:
954     case BUILT_IN_MEMCPY:
955     case BUILT_IN_MEMCPY_CHK:
956     case BUILT_IN_MEMCPY_CHKP:
957     case BUILT_IN_MEMCPY_CHK_CHKP:
958     case BUILT_IN_MEMPCPY:
959     case BUILT_IN_MEMPCPY_CHK:
960     case BUILT_IN_MEMPCPY_CHKP:
961     case BUILT_IN_MEMPCPY_CHK_CHKP:
962     case BUILT_IN_MEMSET:
963     case BUILT_IN_STPCPY:
964     case BUILT_IN_STPCPY_CHK:
965     case BUILT_IN_STPCPY_CHKP:
966     case BUILT_IN_STPCPY_CHK_CHKP:
967     case BUILT_IN_STRCAT:
968     case BUILT_IN_STRCAT_CHK:
969     case BUILT_IN_STRCAT_CHKP:
970     case BUILT_IN_STRCAT_CHK_CHKP:
971     case BUILT_IN_STRCPY:
972     case BUILT_IN_STRCPY_CHK:
973     case BUILT_IN_STRCPY_CHKP:
974     case BUILT_IN_STRCPY_CHK_CHKP:
975       /* The above functions should be neither const nor pure.  Punt if they
976 	 aren't.  */
977       if (gimple_vdef (stmt) == NULL_TREE || gimple_vuse (stmt) == NULL_TREE)
978 	return false;
979       break;
980 
981     default:
982       break;
983     }
984 
985   return true;
986 }
987 
988 /* If the last .MEM setter statement before STMT is
989    memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
990    and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
991    just memcpy (x, y, strlen (y)).  SI must be the zero length
992    strinfo.  */
993 
994 static void
995 adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
996 {
997   tree vuse, callee, len;
998   struct laststmt_struct last = laststmt;
999   strinfo *lastsi, *firstsi;
1000   unsigned len_arg_no = 2;
1001 
1002   laststmt.stmt = NULL;
1003   laststmt.len = NULL_TREE;
1004   laststmt.stridx = 0;
1005 
1006   if (last.stmt == NULL)
1007     return;
1008 
1009   vuse = gimple_vuse (stmt);
1010   if (vuse == NULL_TREE
1011       || SSA_NAME_DEF_STMT (vuse) != last.stmt
1012       || !has_single_use (vuse))
1013     return;
1014 
1015   gcc_assert (last.stridx > 0);
1016   lastsi = get_strinfo (last.stridx);
1017   if (lastsi == NULL)
1018     return;
1019 
1020   if (lastsi != si)
1021     {
1022       if (lastsi->first == 0 || lastsi->first != si->first)
1023 	return;
1024 
1025       firstsi = verify_related_strinfos (si);
1026       if (firstsi == NULL)
1027 	return;
1028       while (firstsi != lastsi)
1029 	{
1030 	  strinfo *nextsi;
1031 	  if (firstsi->next == 0)
1032 	    return;
1033 	  nextsi = get_strinfo (firstsi->next);
1034 	  if (nextsi == NULL
1035 	      || nextsi->prev != firstsi->idx
1036 	      || nextsi->first != si->first)
1037 	    return;
1038 	  firstsi = nextsi;
1039 	}
1040     }
1041 
1042   if (!is_strcat)
1043     {
1044       if (si->length == NULL_TREE || !integer_zerop (si->length))
1045 	return;
1046     }
1047 
1048   if (is_gimple_assign (last.stmt))
1049     {
1050       gimple_stmt_iterator gsi;
1051 
1052       if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
1053 	return;
1054       if (stmt_could_throw_p (last.stmt))
1055 	return;
1056       gsi = gsi_for_stmt (last.stmt);
1057       unlink_stmt_vdef (last.stmt);
1058       release_defs (last.stmt);
1059       gsi_remove (&gsi, true);
1060       return;
1061     }
1062 
1063   if (!valid_builtin_call (last.stmt))
1064     return;
1065 
1066   callee = gimple_call_fndecl (last.stmt);
1067   switch (DECL_FUNCTION_CODE (callee))
1068     {
1069     case BUILT_IN_MEMCPY:
1070     case BUILT_IN_MEMCPY_CHK:
1071       break;
1072     case BUILT_IN_MEMCPY_CHKP:
1073     case BUILT_IN_MEMCPY_CHK_CHKP:
1074       len_arg_no = 4;
1075       break;
1076     default:
1077       return;
1078     }
1079 
1080   len = gimple_call_arg (last.stmt, len_arg_no);
1081   if (tree_fits_uhwi_p (len))
1082     {
1083       if (!tree_fits_uhwi_p (last.len)
1084 	  || integer_zerop (len)
1085 	  || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1)
1086 	return;
1087       /* Don't adjust the length if it is divisible by 4, it is more efficient
1088 	 to store the extra '\0' in that case.  */
1089       if ((tree_to_uhwi (len) & 3) == 0)
1090 	return;
1091     }
1092   else if (TREE_CODE (len) == SSA_NAME)
1093     {
1094       gimple *def_stmt = SSA_NAME_DEF_STMT (len);
1095       if (!is_gimple_assign (def_stmt)
1096 	  || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1097 	  || gimple_assign_rhs1 (def_stmt) != last.len
1098 	  || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1099 	return;
1100     }
1101   else
1102     return;
1103 
1104   gimple_call_set_arg (last.stmt, len_arg_no, last.len);
1105   update_stmt (last.stmt);
1106 }
1107 
1108 /* Handle a strlen call.  If strlen of the argument is known, replace
1109    the strlen call with the known value, otherwise remember that strlen
1110    of the argument is stored in the lhs SSA_NAME.  */
1111 
1112 static void
1113 handle_builtin_strlen (gimple_stmt_iterator *gsi)
1114 {
1115   int idx;
1116   tree src;
1117   gimple *stmt = gsi_stmt (*gsi);
1118   tree lhs = gimple_call_lhs (stmt);
1119 
1120   if (lhs == NULL_TREE)
1121     return;
1122 
1123   src = gimple_call_arg (stmt, 0);
1124   idx = get_stridx (src);
1125   if (idx)
1126     {
1127       strinfo *si = NULL;
1128       tree rhs;
1129 
1130       if (idx < 0)
1131 	rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
1132       else
1133 	{
1134 	  rhs = NULL_TREE;
1135 	  si = get_strinfo (idx);
1136 	  if (si != NULL)
1137 	    rhs = get_string_length (si);
1138 	}
1139       if (rhs != NULL_TREE)
1140 	{
1141 	  if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1142 	    {
1143 	      fprintf (dump_file, "Optimizing: ");
1144 	      print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1145 	    }
1146 	  rhs = unshare_expr (rhs);
1147 	  if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
1148 	    rhs = fold_convert_loc (gimple_location (stmt),
1149 				    TREE_TYPE (lhs), rhs);
1150 	  if (!update_call_from_tree (gsi, rhs))
1151 	    gimplify_and_update_call_from_tree (gsi, rhs);
1152 	  stmt = gsi_stmt (*gsi);
1153 	  update_stmt (stmt);
1154 	  if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1155 	    {
1156 	      fprintf (dump_file, "into: ");
1157 	      print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1158 	    }
1159 	  if (si != NULL
1160 	      && TREE_CODE (si->length) != SSA_NAME
1161 	      && TREE_CODE (si->length) != INTEGER_CST
1162 	      && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1163 	    {
1164 	      si = unshare_strinfo (si);
1165 	      si->length = lhs;
1166 	    }
1167 	  return;
1168 	}
1169     }
1170   if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1171     return;
1172   if (idx == 0)
1173     idx = new_stridx (src);
1174   else if (get_strinfo (idx) != NULL)
1175     return;
1176   if (idx)
1177     {
1178       strinfo *si = new_strinfo (src, idx, lhs);
1179       set_strinfo (idx, si);
1180       find_equal_ptrs (src, idx);
1181     }
1182 }
1183 
1184 /* Handle a strchr call.  If strlen of the first argument is known, replace
1185    the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1186    that lhs of the call is endptr and strlen of the argument is endptr - x.  */
1187 
1188 static void
1189 handle_builtin_strchr (gimple_stmt_iterator *gsi)
1190 {
1191   int idx;
1192   tree src;
1193   gimple *stmt = gsi_stmt (*gsi);
1194   tree lhs = gimple_call_lhs (stmt);
1195   bool with_bounds = gimple_call_with_bounds_p (stmt);
1196 
1197   if (lhs == NULL_TREE)
1198     return;
1199 
1200   if (!integer_zerop (gimple_call_arg (stmt, with_bounds ? 2 : 1)))
1201     return;
1202 
1203   src = gimple_call_arg (stmt, 0);
1204   idx = get_stridx (src);
1205   if (idx)
1206     {
1207       strinfo *si = NULL;
1208       tree rhs;
1209 
1210       if (idx < 0)
1211 	rhs = build_int_cst (size_type_node, ~idx);
1212       else
1213 	{
1214 	  rhs = NULL_TREE;
1215 	  si = get_strinfo (idx);
1216 	  if (si != NULL)
1217 	    rhs = get_string_length (si);
1218 	}
1219       if (rhs != NULL_TREE)
1220 	{
1221 	  location_t loc = gimple_location (stmt);
1222 
1223 	  if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1224 	    {
1225 	      fprintf (dump_file, "Optimizing: ");
1226 	      print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1227 	    }
1228 	  if (si != NULL && si->endptr != NULL_TREE)
1229 	    {
1230 	      rhs = unshare_expr (si->endptr);
1231 	      if (!useless_type_conversion_p (TREE_TYPE (lhs),
1232 					      TREE_TYPE (rhs)))
1233 		rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1234 	    }
1235 	  else
1236 	    {
1237 	      rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
1238 	      rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1239 				     TREE_TYPE (src), src, rhs);
1240 	      if (!useless_type_conversion_p (TREE_TYPE (lhs),
1241 					      TREE_TYPE (rhs)))
1242 		rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1243 	    }
1244 	  if (!update_call_from_tree (gsi, rhs))
1245 	    gimplify_and_update_call_from_tree (gsi, rhs);
1246 	  stmt = gsi_stmt (*gsi);
1247 	  update_stmt (stmt);
1248 	  if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1249 	    {
1250 	      fprintf (dump_file, "into: ");
1251 	      print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1252 	    }
1253 	  if (si != NULL
1254 	      && si->endptr == NULL_TREE
1255 	      && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1256 	    {
1257 	      si = unshare_strinfo (si);
1258 	      si->endptr = lhs;
1259 	    }
1260 	  zero_length_string (lhs, si);
1261 	  return;
1262 	}
1263     }
1264   if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1265     return;
1266   if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1267     {
1268       if (idx == 0)
1269 	idx = new_stridx (src);
1270       else if (get_strinfo (idx) != NULL)
1271 	{
1272 	  zero_length_string (lhs, NULL);
1273 	  return;
1274 	}
1275       if (idx)
1276 	{
1277 	  location_t loc = gimple_location (stmt);
1278 	  tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1279 	  tree srcu = fold_convert_loc (loc, size_type_node, src);
1280 	  tree length = fold_build2_loc (loc, MINUS_EXPR,
1281 					 size_type_node, lhsu, srcu);
1282 	  strinfo *si = new_strinfo (src, idx, length);
1283 	  si->endptr = lhs;
1284 	  set_strinfo (idx, si);
1285 	  find_equal_ptrs (src, idx);
1286 	  zero_length_string (lhs, si);
1287 	}
1288     }
1289   else
1290     zero_length_string (lhs, NULL);
1291 }
1292 
1293 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1294    If strlen of the second argument is known, strlen of the first argument
1295    is the same after this call.  Furthermore, attempt to convert it to
1296    memcpy.  */
1297 
1298 static void
1299 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1300 {
1301   int idx, didx;
1302   tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1303   bool success;
1304   gimple *stmt = gsi_stmt (*gsi);
1305   strinfo *si, *dsi, *olddsi, *zsi;
1306   location_t loc;
1307   bool with_bounds = gimple_call_with_bounds_p (stmt);
1308 
1309   src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1310   dst = gimple_call_arg (stmt, 0);
1311   lhs = gimple_call_lhs (stmt);
1312   idx = get_stridx (src);
1313   si = NULL;
1314   if (idx > 0)
1315     si = get_strinfo (idx);
1316 
1317   didx = get_stridx (dst);
1318   olddsi = NULL;
1319   oldlen = NULL_TREE;
1320   if (didx > 0)
1321     olddsi = get_strinfo (didx);
1322   else if (didx < 0)
1323     return;
1324 
1325   if (olddsi != NULL)
1326     adjust_last_stmt (olddsi, stmt, false);
1327 
1328   srclen = NULL_TREE;
1329   if (si != NULL)
1330     srclen = get_string_length (si);
1331   else if (idx < 0)
1332     srclen = build_int_cst (size_type_node, ~idx);
1333 
1334   loc = gimple_location (stmt);
1335   if (srclen == NULL_TREE)
1336     switch (bcode)
1337       {
1338       case BUILT_IN_STRCPY:
1339       case BUILT_IN_STRCPY_CHK:
1340       case BUILT_IN_STRCPY_CHKP:
1341       case BUILT_IN_STRCPY_CHK_CHKP:
1342 	if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1343 	  return;
1344 	break;
1345       case BUILT_IN_STPCPY:
1346       case BUILT_IN_STPCPY_CHK:
1347       case BUILT_IN_STPCPY_CHKP:
1348       case BUILT_IN_STPCPY_CHK_CHKP:
1349 	if (lhs == NULL_TREE)
1350 	  return;
1351 	else
1352 	  {
1353 	    tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1354 	    srclen = fold_convert_loc (loc, size_type_node, dst);
1355 	    srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1356 				      lhsuint, srclen);
1357 	  }
1358 	break;
1359       default:
1360 	gcc_unreachable ();
1361       }
1362 
1363   if (didx == 0)
1364     {
1365       didx = new_stridx (dst);
1366       if (didx == 0)
1367 	return;
1368     }
1369   if (olddsi != NULL)
1370     {
1371       oldlen = olddsi->length;
1372       dsi = unshare_strinfo (olddsi);
1373       dsi->length = srclen;
1374       /* Break the chain, so adjust_related_strinfo on later pointers in
1375 	 the chain won't adjust this one anymore.  */
1376       dsi->next = 0;
1377       dsi->stmt = NULL;
1378       dsi->endptr = NULL_TREE;
1379     }
1380   else
1381     {
1382       dsi = new_strinfo (dst, didx, srclen);
1383       set_strinfo (didx, dsi);
1384       find_equal_ptrs (dst, didx);
1385     }
1386   dsi->writable = true;
1387   dsi->dont_invalidate = true;
1388 
1389   if (dsi->length == NULL_TREE)
1390     {
1391       strinfo *chainsi;
1392 
1393       /* If string length of src is unknown, use delayed length
1394 	 computation.  If string lenth of dst will be needed, it
1395 	 can be computed by transforming this strcpy call into
1396 	 stpcpy and subtracting dst from the return value.  */
1397 
1398       /* Look for earlier strings whose length could be determined if
1399 	 this strcpy is turned into an stpcpy.  */
1400 
1401       if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1402 	{
1403 	  for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1404 	    {
1405 	      /* When setting a stmt for delayed length computation
1406 		 prevent all strinfos through dsi from being
1407 		 invalidated.  */
1408 	      chainsi = unshare_strinfo (chainsi);
1409 	      chainsi->stmt = stmt;
1410 	      chainsi->length = NULL_TREE;
1411 	      chainsi->endptr = NULL_TREE;
1412 	      chainsi->dont_invalidate = true;
1413 	    }
1414 	}
1415       dsi->stmt = stmt;
1416       return;
1417     }
1418 
1419   if (olddsi != NULL)
1420     {
1421       tree adj = NULL_TREE;
1422       if (oldlen == NULL_TREE)
1423 	;
1424       else if (integer_zerop (oldlen))
1425 	adj = srclen;
1426       else if (TREE_CODE (oldlen) == INTEGER_CST
1427 	       || TREE_CODE (srclen) == INTEGER_CST)
1428 	adj = fold_build2_loc (loc, MINUS_EXPR,
1429 			       TREE_TYPE (srclen), srclen,
1430 			       fold_convert_loc (loc, TREE_TYPE (srclen),
1431 						 oldlen));
1432       if (adj != NULL_TREE)
1433 	adjust_related_strinfos (loc, dsi, adj);
1434       else
1435 	dsi->prev = 0;
1436     }
1437   /* strcpy src may not overlap dst, so src doesn't need to be
1438      invalidated either.  */
1439   if (si != NULL)
1440     si->dont_invalidate = true;
1441 
1442   fn = NULL_TREE;
1443   zsi = NULL;
1444   switch (bcode)
1445     {
1446     case BUILT_IN_STRCPY:
1447     case BUILT_IN_STRCPY_CHKP:
1448       fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1449       if (lhs)
1450 	ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1451       break;
1452     case BUILT_IN_STRCPY_CHK:
1453     case BUILT_IN_STRCPY_CHK_CHKP:
1454       fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1455       if (lhs)
1456 	ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1457       break;
1458     case BUILT_IN_STPCPY:
1459     case BUILT_IN_STPCPY_CHKP:
1460       /* This would need adjustment of the lhs (subtract one),
1461 	 or detection that the trailing '\0' doesn't need to be
1462 	 written, if it will be immediately overwritten.
1463       fn = builtin_decl_explicit (BUILT_IN_MEMPCPY);  */
1464       if (lhs)
1465 	{
1466 	  dsi->endptr = lhs;
1467 	  zsi = zero_length_string (lhs, dsi);
1468 	}
1469       break;
1470     case BUILT_IN_STPCPY_CHK:
1471     case BUILT_IN_STPCPY_CHK_CHKP:
1472       /* This would need adjustment of the lhs (subtract one),
1473 	 or detection that the trailing '\0' doesn't need to be
1474 	 written, if it will be immediately overwritten.
1475       fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK);  */
1476       if (lhs)
1477 	{
1478 	  dsi->endptr = lhs;
1479 	  zsi = zero_length_string (lhs, dsi);
1480 	}
1481       break;
1482     default:
1483       gcc_unreachable ();
1484     }
1485   if (zsi != NULL)
1486     zsi->dont_invalidate = true;
1487 
1488   if (fn == NULL_TREE)
1489     return;
1490 
1491   args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1492   type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1493 
1494   len = fold_convert_loc (loc, type, unshare_expr (srclen));
1495   len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1496   len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1497 				  GSI_SAME_STMT);
1498   if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1499     {
1500       fprintf (dump_file, "Optimizing: ");
1501       print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1502     }
1503   if (with_bounds)
1504     {
1505       fn = chkp_maybe_create_clone (fn)->decl;
1506       if (gimple_call_num_args (stmt) == 4)
1507 	success = update_gimple_call (gsi, fn, 5, dst,
1508 				      gimple_call_arg (stmt, 1),
1509 				      src,
1510 				      gimple_call_arg (stmt, 3),
1511 				      len);
1512       else
1513 	success = update_gimple_call (gsi, fn, 6, dst,
1514 				      gimple_call_arg (stmt, 1),
1515 				      src,
1516 				      gimple_call_arg (stmt, 3),
1517 				      len,
1518 				      gimple_call_arg (stmt, 4));
1519     }
1520   else
1521     if (gimple_call_num_args (stmt) == 2)
1522       success = update_gimple_call (gsi, fn, 3, dst, src, len);
1523     else
1524       success = update_gimple_call (gsi, fn, 4, dst, src, len,
1525 				    gimple_call_arg (stmt, 2));
1526   if (success)
1527     {
1528       stmt = gsi_stmt (*gsi);
1529       gimple_call_set_with_bounds (stmt, with_bounds);
1530       update_stmt (stmt);
1531       if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1532 	{
1533 	  fprintf (dump_file, "into: ");
1534 	  print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1535 	}
1536       /* Allow adjust_last_stmt to decrease this memcpy's size.  */
1537       laststmt.stmt = stmt;
1538       laststmt.len = srclen;
1539       laststmt.stridx = dsi->idx;
1540     }
1541   else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1542     fprintf (dump_file, "not possible.\n");
1543 }
1544 
1545 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1546    If strlen of the second argument is known and length of the third argument
1547    is that plus one, strlen of the first argument is the same after this
1548    call.  */
1549 
1550 static void
1551 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1552 {
1553   int idx, didx;
1554   tree src, dst, len, lhs, oldlen, newlen;
1555   gimple *stmt = gsi_stmt (*gsi);
1556   strinfo *si, *dsi, *olddsi;
1557   bool with_bounds = gimple_call_with_bounds_p (stmt);
1558 
1559   len = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1560   src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1561   dst = gimple_call_arg (stmt, 0);
1562   idx = get_stridx (src);
1563   if (idx == 0)
1564     return;
1565 
1566   didx = get_stridx (dst);
1567   olddsi = NULL;
1568   if (didx > 0)
1569     olddsi = get_strinfo (didx);
1570   else if (didx < 0)
1571     return;
1572 
1573   if (olddsi != NULL
1574       && tree_fits_uhwi_p (len)
1575       && !integer_zerop (len))
1576     adjust_last_stmt (olddsi, stmt, false);
1577 
1578   if (idx > 0)
1579     {
1580       gimple *def_stmt;
1581 
1582       /* Handle memcpy (x, y, l) where l is strlen (y) + 1.  */
1583       si = get_strinfo (idx);
1584       if (si == NULL || si->length == NULL_TREE)
1585 	return;
1586       if (TREE_CODE (len) != SSA_NAME)
1587 	return;
1588       def_stmt = SSA_NAME_DEF_STMT (len);
1589       if (!is_gimple_assign (def_stmt)
1590 	  || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1591 	  || gimple_assign_rhs1 (def_stmt) != si->length
1592 	  || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1593 	return;
1594     }
1595   else
1596     {
1597       si = NULL;
1598       /* Handle memcpy (x, "abcd", 5) or
1599 	 memcpy (x, "abc\0uvw", 7).  */
1600       if (!tree_fits_uhwi_p (len)
1601 	  || tree_to_uhwi (len) <= (unsigned HOST_WIDE_INT) ~idx)
1602 	return;
1603     }
1604 
1605   if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1606     adjust_last_stmt (olddsi, stmt, false);
1607 
1608   if (didx == 0)
1609     {
1610       didx = new_stridx (dst);
1611       if (didx == 0)
1612 	return;
1613     }
1614   if (si != NULL)
1615     newlen = si->length;
1616   else
1617     newlen = build_int_cst (size_type_node, ~idx);
1618   oldlen = NULL_TREE;
1619   if (olddsi != NULL)
1620     {
1621       dsi = unshare_strinfo (olddsi);
1622       oldlen = olddsi->length;
1623       dsi->length = newlen;
1624       /* Break the chain, so adjust_related_strinfo on later pointers in
1625 	 the chain won't adjust this one anymore.  */
1626       dsi->next = 0;
1627       dsi->stmt = NULL;
1628       dsi->endptr = NULL_TREE;
1629     }
1630   else
1631     {
1632       dsi = new_strinfo (dst, didx, newlen);
1633       set_strinfo (didx, dsi);
1634       find_equal_ptrs (dst, didx);
1635     }
1636   dsi->writable = true;
1637   dsi->dont_invalidate = true;
1638   if (olddsi != NULL)
1639     {
1640       tree adj = NULL_TREE;
1641       location_t loc = gimple_location (stmt);
1642       if (oldlen == NULL_TREE)
1643 	;
1644       else if (integer_zerop (oldlen))
1645 	adj = dsi->length;
1646       else if (TREE_CODE (oldlen) == INTEGER_CST
1647 	       || TREE_CODE (dsi->length) == INTEGER_CST)
1648 	adj = fold_build2_loc (loc, MINUS_EXPR,
1649 			       TREE_TYPE (dsi->length), dsi->length,
1650 			       fold_convert_loc (loc, TREE_TYPE (dsi->length),
1651 						 oldlen));
1652       if (adj != NULL_TREE)
1653 	adjust_related_strinfos (loc, dsi, adj);
1654       else
1655 	dsi->prev = 0;
1656     }
1657   /* memcpy src may not overlap dst, so src doesn't need to be
1658      invalidated either.  */
1659   if (si != NULL)
1660     si->dont_invalidate = true;
1661 
1662   lhs = gimple_call_lhs (stmt);
1663   switch (bcode)
1664     {
1665     case BUILT_IN_MEMCPY:
1666     case BUILT_IN_MEMCPY_CHK:
1667     case BUILT_IN_MEMCPY_CHKP:
1668     case BUILT_IN_MEMCPY_CHK_CHKP:
1669       /* Allow adjust_last_stmt to decrease this memcpy's size.  */
1670       laststmt.stmt = stmt;
1671       laststmt.len = dsi->length;
1672       laststmt.stridx = dsi->idx;
1673       if (lhs)
1674 	ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1675       break;
1676     case BUILT_IN_MEMPCPY:
1677     case BUILT_IN_MEMPCPY_CHK:
1678     case BUILT_IN_MEMPCPY_CHKP:
1679     case BUILT_IN_MEMPCPY_CHK_CHKP:
1680       break;
1681     default:
1682       gcc_unreachable ();
1683     }
1684 }
1685 
1686 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1687    If strlen of the second argument is known, strlen of the first argument
1688    is increased by the length of the second argument.  Furthermore, attempt
1689    to convert it to memcpy/strcpy if the length of the first argument
1690    is known.  */
1691 
1692 static void
1693 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1694 {
1695   int idx, didx;
1696   tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1697   bool success;
1698   gimple *stmt = gsi_stmt (*gsi);
1699   strinfo *si, *dsi;
1700   location_t loc;
1701   bool with_bounds = gimple_call_with_bounds_p (stmt);
1702 
1703   src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1704   dst = gimple_call_arg (stmt, 0);
1705   lhs = gimple_call_lhs (stmt);
1706 
1707   didx = get_stridx (dst);
1708   if (didx < 0)
1709     return;
1710 
1711   dsi = NULL;
1712   if (didx > 0)
1713     dsi = get_strinfo (didx);
1714   if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1715     {
1716       /* strcat (p, q) can be transformed into
1717 	 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1718 	 with length endptr - p if we need to compute the length
1719 	 later on.  Don't do this transformation if we don't need
1720 	 it.  */
1721       if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1722 	{
1723 	  if (didx == 0)
1724 	    {
1725 	      didx = new_stridx (dst);
1726 	      if (didx == 0)
1727 		return;
1728 	    }
1729 	  if (dsi == NULL)
1730 	    {
1731 	      dsi = new_strinfo (dst, didx, NULL_TREE);
1732 	      set_strinfo (didx, dsi);
1733 	      find_equal_ptrs (dst, didx);
1734 	    }
1735 	  else
1736 	    {
1737 	      dsi = unshare_strinfo (dsi);
1738 	      dsi->length = NULL_TREE;
1739 	      dsi->next = 0;
1740 	      dsi->endptr = NULL_TREE;
1741 	    }
1742 	  dsi->writable = true;
1743 	  dsi->stmt = stmt;
1744 	  dsi->dont_invalidate = true;
1745 	}
1746       return;
1747     }
1748 
1749   srclen = NULL_TREE;
1750   si = NULL;
1751   idx = get_stridx (src);
1752   if (idx < 0)
1753     srclen = build_int_cst (size_type_node, ~idx);
1754   else if (idx > 0)
1755     {
1756       si = get_strinfo (idx);
1757       if (si != NULL)
1758 	srclen = get_string_length (si);
1759     }
1760 
1761   loc = gimple_location (stmt);
1762   dstlen = dsi->length;
1763   endptr = dsi->endptr;
1764 
1765   dsi = unshare_strinfo (dsi);
1766   dsi->endptr = NULL_TREE;
1767   dsi->stmt = NULL;
1768   dsi->writable = true;
1769 
1770   if (srclen != NULL_TREE)
1771     {
1772       dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1773 				     dsi->length, srclen);
1774       adjust_related_strinfos (loc, dsi, srclen);
1775       dsi->dont_invalidate = true;
1776     }
1777   else
1778     {
1779       dsi->length = NULL;
1780       if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1781 	dsi->dont_invalidate = true;
1782     }
1783 
1784   if (si != NULL)
1785     /* strcat src may not overlap dst, so src doesn't need to be
1786        invalidated either.  */
1787     si->dont_invalidate = true;
1788 
1789   /* For now.  Could remove the lhs from the call and add
1790      lhs = dst; afterwards.  */
1791   if (lhs)
1792     return;
1793 
1794   fn = NULL_TREE;
1795   objsz = NULL_TREE;
1796   switch (bcode)
1797     {
1798     case BUILT_IN_STRCAT:
1799     case BUILT_IN_STRCAT_CHKP:
1800       if (srclen != NULL_TREE)
1801 	fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1802       else
1803 	fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1804       break;
1805     case BUILT_IN_STRCAT_CHK:
1806     case BUILT_IN_STRCAT_CHK_CHKP:
1807       if (srclen != NULL_TREE)
1808 	fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1809       else
1810 	fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1811       objsz = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1812       break;
1813     default:
1814       gcc_unreachable ();
1815     }
1816 
1817   if (fn == NULL_TREE)
1818     return;
1819 
1820   len = NULL_TREE;
1821   if (srclen != NULL_TREE)
1822     {
1823       args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1824       type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1825 
1826       len = fold_convert_loc (loc, type, unshare_expr (srclen));
1827       len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1828 			     build_int_cst (type, 1));
1829       len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1830 				      GSI_SAME_STMT);
1831     }
1832   if (endptr)
1833     dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1834   else
1835     dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1836 			   TREE_TYPE (dst), unshare_expr (dst),
1837 			   fold_convert_loc (loc, sizetype,
1838 					     unshare_expr (dstlen)));
1839   dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1840 				  GSI_SAME_STMT);
1841   if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1842     {
1843       fprintf (dump_file, "Optimizing: ");
1844       print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1845     }
1846   if (with_bounds)
1847     {
1848       fn = chkp_maybe_create_clone (fn)->decl;
1849       if (srclen != NULL_TREE)
1850 	success = update_gimple_call (gsi, fn, 5 + (objsz != NULL_TREE),
1851 				      dst,
1852 				      gimple_call_arg (stmt, 1),
1853 				      src,
1854 				      gimple_call_arg (stmt, 3),
1855 				      len, objsz);
1856       else
1857 	success = update_gimple_call (gsi, fn, 4 + (objsz != NULL_TREE),
1858 				      dst,
1859 				      gimple_call_arg (stmt, 1),
1860 				      src,
1861 				      gimple_call_arg (stmt, 3),
1862 				      objsz);
1863     }
1864   else
1865     if (srclen != NULL_TREE)
1866       success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1867 				    dst, src, len, objsz);
1868     else
1869       success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1870 				    dst, src, objsz);
1871   if (success)
1872     {
1873       stmt = gsi_stmt (*gsi);
1874       gimple_call_set_with_bounds (stmt, with_bounds);
1875       update_stmt (stmt);
1876       if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1877 	{
1878 	  fprintf (dump_file, "into: ");
1879 	  print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1880 	}
1881       /* If srclen == NULL, note that current string length can be
1882 	 computed by transforming this strcpy into stpcpy.  */
1883       if (srclen == NULL_TREE && dsi->dont_invalidate)
1884 	dsi->stmt = stmt;
1885       adjust_last_stmt (dsi, stmt, true);
1886       if (srclen != NULL_TREE)
1887 	{
1888 	  laststmt.stmt = stmt;
1889 	  laststmt.len = srclen;
1890 	  laststmt.stridx = dsi->idx;
1891 	}
1892     }
1893   else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1894     fprintf (dump_file, "not possible.\n");
1895 }
1896 
1897 /* Handle a call to malloc or calloc.  */
1898 
1899 static void
1900 handle_builtin_malloc (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1901 {
1902   gimple *stmt = gsi_stmt (*gsi);
1903   tree lhs = gimple_call_lhs (stmt);
1904   if (lhs == NULL_TREE)
1905     return;
1906 
1907   gcc_assert (get_stridx (lhs) == 0);
1908   int idx = new_stridx (lhs);
1909   tree length = NULL_TREE;
1910   if (bcode == BUILT_IN_CALLOC)
1911     length = build_int_cst (size_type_node, 0);
1912   strinfo *si = new_strinfo (lhs, idx, length);
1913   if (bcode == BUILT_IN_CALLOC)
1914     si->endptr = lhs;
1915   set_strinfo (idx, si);
1916   si->writable = true;
1917   si->stmt = stmt;
1918   si->dont_invalidate = true;
1919 }
1920 
1921 /* Handle a call to memset.
1922    After a call to calloc, memset(,0,) is unnecessary.
1923    memset(malloc(n),0,n) is calloc(n,1).  */
1924 
1925 static bool
1926 handle_builtin_memset (gimple_stmt_iterator *gsi)
1927 {
1928   gimple *stmt2 = gsi_stmt (*gsi);
1929   if (!integer_zerop (gimple_call_arg (stmt2, 1)))
1930     return true;
1931   tree ptr = gimple_call_arg (stmt2, 0);
1932   int idx1 = get_stridx (ptr);
1933   if (idx1 <= 0)
1934     return true;
1935   strinfo *si1 = get_strinfo (idx1);
1936   if (!si1)
1937     return true;
1938   gimple *stmt1 = si1->stmt;
1939   if (!stmt1 || !is_gimple_call (stmt1))
1940     return true;
1941   tree callee1 = gimple_call_fndecl (stmt1);
1942   if (!valid_builtin_call (stmt1))
1943     return true;
1944   enum built_in_function code1 = DECL_FUNCTION_CODE (callee1);
1945   tree size = gimple_call_arg (stmt2, 2);
1946   if (code1 == BUILT_IN_CALLOC)
1947     /* Not touching stmt1 */ ;
1948   else if (code1 == BUILT_IN_MALLOC
1949 	   && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0))
1950     {
1951       gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1);
1952       update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2,
1953 			  size, build_one_cst (size_type_node));
1954       si1->length = build_int_cst (size_type_node, 0);
1955       si1->stmt = gsi_stmt (gsi1);
1956     }
1957   else
1958     return true;
1959   tree lhs = gimple_call_lhs (stmt2);
1960   unlink_stmt_vdef (stmt2);
1961   if (lhs)
1962     {
1963       gimple *assign = gimple_build_assign (lhs, ptr);
1964       gsi_replace (gsi, assign, false);
1965     }
1966   else
1967     {
1968       gsi_remove (gsi, true);
1969       release_defs (stmt2);
1970     }
1971 
1972   return false;
1973 }
1974 
1975 /* Handle a call to memcmp.  We try to handle small comparisons by
1976    converting them to load and compare, and replacing the call to memcmp
1977    with a __builtin_memcmp_eq call where possible.  */
1978 
1979 static bool
1980 handle_builtin_memcmp (gimple_stmt_iterator *gsi)
1981 {
1982   gcall *stmt2 = as_a <gcall *> (gsi_stmt (*gsi));
1983   tree res = gimple_call_lhs (stmt2);
1984   tree arg1 = gimple_call_arg (stmt2, 0);
1985   tree arg2 = gimple_call_arg (stmt2, 1);
1986   tree len = gimple_call_arg (stmt2, 2);
1987   unsigned HOST_WIDE_INT leni;
1988   use_operand_p use_p;
1989   imm_use_iterator iter;
1990 
1991   if (!res)
1992     return true;
1993 
1994   FOR_EACH_IMM_USE_FAST (use_p, iter, res)
1995     {
1996       gimple *ustmt = USE_STMT (use_p);
1997 
1998       if (is_gimple_debug (ustmt))
1999 	continue;
2000       if (gimple_code (ustmt) == GIMPLE_ASSIGN)
2001 	{
2002 	  gassign *asgn = as_a <gassign *> (ustmt);
2003 	  tree_code code = gimple_assign_rhs_code (asgn);
2004 	  if ((code != EQ_EXPR && code != NE_EXPR)
2005 	      || !integer_zerop (gimple_assign_rhs2 (asgn)))
2006 	    return true;
2007 	}
2008       else if (gimple_code (ustmt) == GIMPLE_COND)
2009 	{
2010 	  tree_code code = gimple_cond_code (ustmt);
2011 	  if ((code != EQ_EXPR && code != NE_EXPR)
2012 	      || !integer_zerop (gimple_cond_rhs (ustmt)))
2013 	    return true;
2014 	}
2015       else
2016 	return true;
2017     }
2018 
2019   if (tree_fits_uhwi_p (len)
2020       && (leni = tree_to_uhwi (len)) <= GET_MODE_SIZE (word_mode)
2021       && pow2p_hwi (leni))
2022     {
2023       leni *= CHAR_TYPE_SIZE;
2024       unsigned align1 = get_pointer_alignment (arg1);
2025       unsigned align2 = get_pointer_alignment (arg2);
2026       unsigned align = MIN (align1, align2);
2027       machine_mode mode = mode_for_size (leni, MODE_INT, 1);
2028       if (mode != BLKmode
2029 	  && (align >= leni || !SLOW_UNALIGNED_ACCESS (mode, align)))
2030 	{
2031 	  location_t loc = gimple_location (stmt2);
2032 	  tree type, off;
2033 	  type = build_nonstandard_integer_type (leni, 1);
2034 	  gcc_assert (GET_MODE_BITSIZE (TYPE_MODE (type)) == leni);
2035 	  tree ptrtype = build_pointer_type_for_mode (char_type_node,
2036 						      ptr_mode, true);
2037 	  off = build_int_cst (ptrtype, 0);
2038 	  arg1 = build2_loc (loc, MEM_REF, type, arg1, off);
2039 	  arg2 = build2_loc (loc, MEM_REF, type, arg2, off);
2040 	  tree tem1 = fold_const_aggregate_ref (arg1);
2041 	  if (tem1)
2042 	    arg1 = tem1;
2043 	  tree tem2 = fold_const_aggregate_ref (arg2);
2044 	  if (tem2)
2045 	    arg2 = tem2;
2046 	  res = fold_convert_loc (loc, TREE_TYPE (res),
2047 				  fold_build2_loc (loc, NE_EXPR,
2048 						   boolean_type_node,
2049 						   arg1, arg2));
2050 	  gimplify_and_update_call_from_tree (gsi, res);
2051 	  return false;
2052 	}
2053     }
2054 
2055   gimple_call_set_fndecl (stmt2, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ));
2056   return false;
2057 }
2058 
2059 /* Handle a POINTER_PLUS_EXPR statement.
2060    For p = "abcd" + 2; compute associated length, or if
2061    p = q + off is pointing to a '\0' character of a string, call
2062    zero_length_string on it.  */
2063 
2064 static void
2065 handle_pointer_plus (gimple_stmt_iterator *gsi)
2066 {
2067   gimple *stmt = gsi_stmt (*gsi);
2068   tree lhs = gimple_assign_lhs (stmt), off;
2069   int idx = get_stridx (gimple_assign_rhs1 (stmt));
2070   strinfo *si, *zsi;
2071 
2072   if (idx == 0)
2073     return;
2074 
2075   if (idx < 0)
2076     {
2077       tree off = gimple_assign_rhs2 (stmt);
2078       if (tree_fits_uhwi_p (off)
2079 	  && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx)
2080 	ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
2081 	    = ~(~idx - (int) tree_to_uhwi (off));
2082       return;
2083     }
2084 
2085   si = get_strinfo (idx);
2086   if (si == NULL || si->length == NULL_TREE)
2087     return;
2088 
2089   off = gimple_assign_rhs2 (stmt);
2090   zsi = NULL;
2091   if (operand_equal_p (si->length, off, 0))
2092     zsi = zero_length_string (lhs, si);
2093   else if (TREE_CODE (off) == SSA_NAME)
2094     {
2095       gimple *def_stmt = SSA_NAME_DEF_STMT (off);
2096       if (gimple_assign_single_p (def_stmt)
2097 	  && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
2098 	zsi = zero_length_string (lhs, si);
2099     }
2100   if (zsi != NULL
2101       && si->endptr != NULL_TREE
2102       && si->endptr != lhs
2103       && TREE_CODE (si->endptr) == SSA_NAME)
2104     {
2105       enum tree_code rhs_code
2106 	= useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
2107 	  ? SSA_NAME : NOP_EXPR;
2108       gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr);
2109       gcc_assert (gsi_stmt (*gsi) == stmt);
2110       update_stmt (stmt);
2111     }
2112 }
2113 
2114 /* Handle a single character store.  */
2115 
2116 static bool
2117 handle_char_store (gimple_stmt_iterator *gsi)
2118 {
2119   int idx = -1;
2120   strinfo *si = NULL;
2121   gimple *stmt = gsi_stmt (*gsi);
2122   tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
2123 
2124   if (TREE_CODE (lhs) == MEM_REF
2125       && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
2126     {
2127       if (integer_zerop (TREE_OPERAND (lhs, 1)))
2128 	{
2129 	  ssaname = TREE_OPERAND (lhs, 0);
2130 	  idx = get_stridx (ssaname);
2131 	}
2132     }
2133   else
2134     idx = get_addr_stridx (lhs, NULL_TREE);
2135 
2136   if (idx > 0)
2137     {
2138       si = get_strinfo (idx);
2139       if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
2140 	{
2141 	  if (initializer_zerop (gimple_assign_rhs1 (stmt)))
2142 	    {
2143 	      /* When storing '\0', the store can be removed
2144 		 if we know it has been stored in the current function.  */
2145 	      if (!stmt_could_throw_p (stmt) && si->writable)
2146 		{
2147 		  unlink_stmt_vdef (stmt);
2148 		  release_defs (stmt);
2149 		  gsi_remove (gsi, true);
2150 		  return false;
2151 		}
2152 	      else
2153 		{
2154 		  si->writable = true;
2155 		  gsi_next (gsi);
2156 		  return false;
2157 		}
2158 	    }
2159 	  else
2160 	    /* Otherwise this statement overwrites the '\0' with
2161 	       something, if the previous stmt was a memcpy,
2162 	       its length may be decreased.  */
2163 	    adjust_last_stmt (si, stmt, false);
2164 	}
2165       else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt)))
2166 	{
2167 	  si = unshare_strinfo (si);
2168 	  si->length = build_int_cst (size_type_node, 0);
2169 	  si->endptr = NULL;
2170 	  si->prev = 0;
2171 	  si->next = 0;
2172 	  si->stmt = NULL;
2173 	  si->first = 0;
2174 	  si->writable = true;
2175 	  if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
2176 	    si->endptr = ssaname;
2177 	  si->dont_invalidate = true;
2178 	}
2179       /* If si->length is non-zero constant, we aren't overwriting '\0',
2180 	 and if we aren't storing '\0', we know that the length of the
2181 	 string and any other zero terminated string in memory remains
2182 	 the same.  In that case we move to the next gimple statement and
2183 	 return to signal the caller that it shouldn't invalidate anything.
2184 
2185 	 This is benefical for cases like:
2186 
2187 	 char p[20];
2188 	 void foo (char *q)
2189 	 {
2190 	   strcpy (p, "foobar");
2191 	   size_t len = strlen (p);        // This can be optimized into 6
2192 	   size_t len2 = strlen (q);        // This has to be computed
2193 	   p[0] = 'X';
2194 	   size_t len3 = strlen (p);        // This can be optimized into 6
2195 	   size_t len4 = strlen (q);        // This can be optimized into len2
2196 	   bar (len, len2, len3, len4);
2197         }
2198 	*/
2199       else if (si != NULL && si->length != NULL_TREE
2200 	       && TREE_CODE (si->length) == INTEGER_CST
2201 	       && integer_nonzerop (gimple_assign_rhs1 (stmt)))
2202 	{
2203 	  gsi_next (gsi);
2204 	  return false;
2205 	}
2206     }
2207   else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
2208     {
2209       if (ssaname)
2210 	{
2211 	  si = zero_length_string (ssaname, NULL);
2212 	  if (si != NULL)
2213 	    si->dont_invalidate = true;
2214 	}
2215       else
2216 	{
2217 	  int idx = new_addr_stridx (lhs);
2218 	  if (idx != 0)
2219 	    {
2220 	      si = new_strinfo (build_fold_addr_expr (lhs), idx,
2221 				build_int_cst (size_type_node, 0));
2222 	      set_strinfo (idx, si);
2223 	      si->dont_invalidate = true;
2224 	    }
2225 	}
2226       if (si != NULL)
2227 	si->writable = true;
2228     }
2229   else if (idx == 0
2230 	   && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
2231 	   && ssaname == NULL_TREE
2232 	   && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
2233     {
2234       size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
2235       HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
2236       if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
2237 	{
2238 	  int idx = new_addr_stridx (lhs);
2239 	  if (idx != 0)
2240 	    {
2241 	      si = new_strinfo (build_fold_addr_expr (lhs), idx,
2242 				build_int_cst (size_type_node, l));
2243 	      set_strinfo (idx, si);
2244 	      si->dont_invalidate = true;
2245 	    }
2246 	}
2247     }
2248 
2249   if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
2250     {
2251       /* Allow adjust_last_stmt to remove it if the stored '\0'
2252 	 is immediately overwritten.  */
2253       laststmt.stmt = stmt;
2254       laststmt.len = build_int_cst (size_type_node, 1);
2255       laststmt.stridx = si->idx;
2256     }
2257   return true;
2258 }
2259 
2260 /* Try to fold strstr (s, t) eq/ne s to strncmp (s, t, strlen (t)) eq/ne 0.  */
2261 
2262 static void
2263 fold_strstr_to_strncmp (tree rhs1, tree rhs2, gimple *stmt)
2264 {
2265   if (TREE_CODE (rhs1) != SSA_NAME
2266       || TREE_CODE (rhs2) != SSA_NAME)
2267     return;
2268 
2269   gimple *call_stmt = NULL;
2270   for (int pass = 0; pass < 2; pass++)
2271     {
2272       gimple *g = SSA_NAME_DEF_STMT (rhs1);
2273       if (gimple_call_builtin_p (g, BUILT_IN_STRSTR)
2274 	  && has_single_use (rhs1)
2275 	  && gimple_call_arg (g, 0) == rhs2)
2276 	{
2277 	  call_stmt = g;
2278 	  break;
2279 	}
2280       std::swap (rhs1, rhs2);
2281     }
2282 
2283   if (call_stmt)
2284     {
2285       tree arg0 = gimple_call_arg (call_stmt, 0);
2286 
2287       if (arg0 == rhs2)
2288 	{
2289 	  tree arg1 = gimple_call_arg (call_stmt, 1);
2290 	  tree arg1_len = NULL_TREE;
2291 	  int idx = get_stridx (arg1);
2292 
2293 	  if (idx)
2294 	    {
2295 	      if (idx < 0)
2296 		arg1_len = build_int_cst (size_type_node, ~idx);
2297 	      else
2298 		{
2299 		  strinfo *si = get_strinfo (idx);
2300 		  if (si)
2301 		    arg1_len = get_string_length (si);
2302 		}
2303 	    }
2304 
2305 	  if (arg1_len != NULL_TREE)
2306 	    {
2307 	      gimple_stmt_iterator gsi = gsi_for_stmt (call_stmt);
2308 	      tree strncmp_decl = builtin_decl_explicit (BUILT_IN_STRNCMP);
2309 
2310 	      if (!is_gimple_val (arg1_len))
2311 		{
2312 		  tree arg1_len_tmp = make_ssa_name (TREE_TYPE (arg1_len));
2313 		  gassign *arg1_stmt = gimple_build_assign (arg1_len_tmp,
2314 							    arg1_len);
2315 		  gsi_insert_before (&gsi, arg1_stmt, GSI_SAME_STMT);
2316 		  arg1_len = arg1_len_tmp;
2317 		}
2318 
2319 	      gcall *strncmp_call = gimple_build_call (strncmp_decl, 3,
2320 						      arg0, arg1, arg1_len);
2321 	      tree strncmp_lhs = make_ssa_name (integer_type_node);
2322 	      gimple_set_vuse (strncmp_call, gimple_vuse (call_stmt));
2323 	      gimple_call_set_lhs (strncmp_call, strncmp_lhs);
2324 	      gsi_remove (&gsi, true);
2325 	      gsi_insert_before (&gsi, strncmp_call, GSI_SAME_STMT);
2326 	      tree zero = build_zero_cst (TREE_TYPE (strncmp_lhs));
2327 
2328 	      if (is_gimple_assign (stmt))
2329 		{
2330 		  if (gimple_assign_rhs_code (stmt) == COND_EXPR)
2331 		    {
2332 		      tree cond = gimple_assign_rhs1 (stmt);
2333 		      TREE_OPERAND (cond, 0) = strncmp_lhs;
2334 		      TREE_OPERAND (cond, 1) = zero;
2335 		    }
2336 		  else
2337 		    {
2338 		      gimple_assign_set_rhs1 (stmt, strncmp_lhs);
2339 		      gimple_assign_set_rhs2 (stmt, zero);
2340 		    }
2341 		}
2342 	      else
2343 		{
2344 		  gcond *cond = as_a<gcond *> (stmt);
2345 		  gimple_cond_set_lhs (cond, strncmp_lhs);
2346 		  gimple_cond_set_rhs (cond, zero);
2347 		}
2348 	      update_stmt (stmt);
2349 	    }
2350 	}
2351     }
2352 }
2353 
2354 /* Attempt to optimize a single statement at *GSI using string length
2355    knowledge.  */
2356 
2357 static bool
2358 strlen_optimize_stmt (gimple_stmt_iterator *gsi)
2359 {
2360   gimple *stmt = gsi_stmt (*gsi);
2361 
2362   if (is_gimple_call (stmt))
2363     {
2364       tree callee = gimple_call_fndecl (stmt);
2365       if (valid_builtin_call (stmt))
2366 	switch (DECL_FUNCTION_CODE (callee))
2367 	  {
2368 	  case BUILT_IN_STRLEN:
2369 	  case BUILT_IN_STRLEN_CHKP:
2370 	    handle_builtin_strlen (gsi);
2371 	    break;
2372 	  case BUILT_IN_STRCHR:
2373 	  case BUILT_IN_STRCHR_CHKP:
2374 	    handle_builtin_strchr (gsi);
2375 	    break;
2376 	  case BUILT_IN_STRCPY:
2377 	  case BUILT_IN_STRCPY_CHK:
2378 	  case BUILT_IN_STPCPY:
2379 	  case BUILT_IN_STPCPY_CHK:
2380 	  case BUILT_IN_STRCPY_CHKP:
2381 	  case BUILT_IN_STRCPY_CHK_CHKP:
2382 	  case BUILT_IN_STPCPY_CHKP:
2383 	  case BUILT_IN_STPCPY_CHK_CHKP:
2384 	    handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
2385 	    break;
2386 	  case BUILT_IN_MEMCPY:
2387 	  case BUILT_IN_MEMCPY_CHK:
2388 	  case BUILT_IN_MEMPCPY:
2389 	  case BUILT_IN_MEMPCPY_CHK:
2390 	  case BUILT_IN_MEMCPY_CHKP:
2391 	  case BUILT_IN_MEMCPY_CHK_CHKP:
2392 	  case BUILT_IN_MEMPCPY_CHKP:
2393 	  case BUILT_IN_MEMPCPY_CHK_CHKP:
2394 	    handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
2395 	    break;
2396 	  case BUILT_IN_STRCAT:
2397 	  case BUILT_IN_STRCAT_CHK:
2398 	  case BUILT_IN_STRCAT_CHKP:
2399 	  case BUILT_IN_STRCAT_CHK_CHKP:
2400 	    handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
2401 	    break;
2402 	  case BUILT_IN_MALLOC:
2403 	  case BUILT_IN_CALLOC:
2404 	    handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi);
2405 	    break;
2406 	  case BUILT_IN_MEMSET:
2407 	    if (!handle_builtin_memset (gsi))
2408 	      return false;
2409 	    break;
2410 	  case BUILT_IN_MEMCMP:
2411 	    if (!handle_builtin_memcmp (gsi))
2412 	      return false;
2413 	    break;
2414 	  default:
2415 	    break;
2416 	  }
2417     }
2418   else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt))
2419     {
2420       tree lhs = gimple_assign_lhs (stmt);
2421 
2422       if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
2423 	{
2424 	  if (gimple_assign_single_p (stmt)
2425 	      || (gimple_assign_cast_p (stmt)
2426 		  && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
2427 	    {
2428 	      int idx = get_stridx (gimple_assign_rhs1 (stmt));
2429 	      ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
2430 	    }
2431 	  else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
2432 	    handle_pointer_plus (gsi);
2433 	}
2434     else if (TREE_CODE (lhs) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
2435       {
2436 	enum tree_code code = gimple_assign_rhs_code (stmt);
2437 	if (code == COND_EXPR)
2438 	  {
2439 	    tree cond = gimple_assign_rhs1 (stmt);
2440 	    enum tree_code cond_code = TREE_CODE (cond);
2441 
2442 	    if (cond_code == EQ_EXPR || cond_code == NE_EXPR)
2443 	      fold_strstr_to_strncmp (TREE_OPERAND (cond, 0),
2444 				      TREE_OPERAND (cond, 1), stmt);
2445 	  }
2446 	else if (code == EQ_EXPR || code == NE_EXPR)
2447 	  fold_strstr_to_strncmp (gimple_assign_rhs1 (stmt),
2448 				  gimple_assign_rhs2 (stmt), stmt);
2449       }
2450     else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
2451 	{
2452 	  tree type = TREE_TYPE (lhs);
2453 	  if (TREE_CODE (type) == ARRAY_TYPE)
2454 	    type = TREE_TYPE (type);
2455 	  if (TREE_CODE (type) == INTEGER_TYPE
2456 	      && TYPE_MODE (type) == TYPE_MODE (char_type_node)
2457 	      && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
2458 	    {
2459 	      if (! handle_char_store (gsi))
2460 		return false;
2461 	    }
2462 	}
2463     }
2464   else if (gcond *cond = dyn_cast<gcond *> (stmt))
2465     {
2466       enum tree_code code = gimple_cond_code (cond);
2467       if (code == EQ_EXPR || code == NE_EXPR)
2468 	fold_strstr_to_strncmp (gimple_cond_lhs (stmt),
2469 				gimple_cond_rhs (stmt), stmt);
2470     }
2471 
2472   if (gimple_vdef (stmt))
2473     maybe_invalidate (stmt);
2474   return true;
2475 }
2476 
2477 /* Recursively call maybe_invalidate on stmts that might be executed
2478    in between dombb and current bb and that contain a vdef.  Stop when
2479    *count stmts are inspected, or if the whole strinfo vector has
2480    been invalidated.  */
2481 
2482 static void
2483 do_invalidate (basic_block dombb, gimple *phi, bitmap visited, int *count)
2484 {
2485   unsigned int i, n = gimple_phi_num_args (phi);
2486 
2487   for (i = 0; i < n; i++)
2488     {
2489       tree vuse = gimple_phi_arg_def (phi, i);
2490       gimple *stmt = SSA_NAME_DEF_STMT (vuse);
2491       basic_block bb = gimple_bb (stmt);
2492       if (bb == NULL
2493 	  || bb == dombb
2494 	  || !bitmap_set_bit (visited, bb->index)
2495 	  || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2496 	continue;
2497       while (1)
2498 	{
2499 	  if (gimple_code (stmt) == GIMPLE_PHI)
2500 	    {
2501 	      do_invalidate (dombb, stmt, visited, count);
2502 	      if (*count == 0)
2503 		return;
2504 	      break;
2505 	    }
2506 	  if (--*count == 0)
2507 	    return;
2508 	  if (!maybe_invalidate (stmt))
2509 	    {
2510 	      *count = 0;
2511 	      return;
2512 	    }
2513 	  vuse = gimple_vuse (stmt);
2514 	  stmt = SSA_NAME_DEF_STMT (vuse);
2515 	  if (gimple_bb (stmt) != bb)
2516 	    {
2517 	      bb = gimple_bb (stmt);
2518 	      if (bb == NULL
2519 		  || bb == dombb
2520 		  || !bitmap_set_bit (visited, bb->index)
2521 		  || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2522 		break;
2523 	    }
2524 	}
2525     }
2526 }
2527 
2528 class strlen_dom_walker : public dom_walker
2529 {
2530 public:
2531   strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
2532 
2533   virtual edge before_dom_children (basic_block);
2534   virtual void after_dom_children (basic_block);
2535 };
2536 
2537 /* Callback for walk_dominator_tree.  Attempt to optimize various
2538    string ops by remembering string lengths pointed by pointer SSA_NAMEs.  */
2539 
2540 edge
2541 strlen_dom_walker::before_dom_children (basic_block bb)
2542 {
2543   basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
2544 
2545   if (dombb == NULL)
2546     stridx_to_strinfo = NULL;
2547   else
2548     {
2549       stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) dombb->aux);
2550       if (stridx_to_strinfo)
2551 	{
2552 	  for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2553 	       gsi_next (&gsi))
2554 	    {
2555 	      gphi *phi = gsi.phi ();
2556 	      if (virtual_operand_p (gimple_phi_result (phi)))
2557 		{
2558 		  bitmap visited = BITMAP_ALLOC (NULL);
2559 		  int count_vdef = 100;
2560 		  do_invalidate (dombb, phi, visited, &count_vdef);
2561 		  BITMAP_FREE (visited);
2562 		  if (count_vdef == 0)
2563 		    {
2564 		      /* If there were too many vdefs in between immediate
2565 			 dominator and current bb, invalidate everything.
2566 			 If stridx_to_strinfo has been unshared, we need
2567 			 to free it, otherwise just set it to NULL.  */
2568 		      if (!strinfo_shared ())
2569 			{
2570 			  unsigned int i;
2571 			  strinfo *si;
2572 
2573 			  for (i = 1;
2574 			       vec_safe_iterate (stridx_to_strinfo, i, &si);
2575 			       ++i)
2576 			    {
2577 			      free_strinfo (si);
2578 			      (*stridx_to_strinfo)[i] = NULL;
2579 			    }
2580 			}
2581 		      else
2582 			stridx_to_strinfo = NULL;
2583 		    }
2584 		  break;
2585 		}
2586 	    }
2587 	}
2588     }
2589 
2590   /* If all PHI arguments have the same string index, the PHI result
2591      has it as well.  */
2592   for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2593        gsi_next (&gsi))
2594     {
2595       gphi *phi = gsi.phi ();
2596       tree result = gimple_phi_result (phi);
2597       if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
2598 	{
2599 	  int idx = get_stridx (gimple_phi_arg_def (phi, 0));
2600 	  if (idx != 0)
2601 	    {
2602 	      unsigned int i, n = gimple_phi_num_args (phi);
2603 	      for (i = 1; i < n; i++)
2604 		if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
2605 		  break;
2606 	      if (i == n)
2607 		ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
2608 	    }
2609 	}
2610     }
2611 
2612   /* Attempt to optimize individual statements.  */
2613   for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2614     if (strlen_optimize_stmt (&gsi))
2615       gsi_next (&gsi);
2616 
2617   bb->aux = stridx_to_strinfo;
2618   if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
2619     (*stridx_to_strinfo)[0] = (strinfo *) bb;
2620   return NULL;
2621 }
2622 
2623 /* Callback for walk_dominator_tree.  Free strinfo vector if it is
2624    owned by the current bb, clear bb->aux.  */
2625 
2626 void
2627 strlen_dom_walker::after_dom_children (basic_block bb)
2628 {
2629   if (bb->aux)
2630     {
2631       stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) bb->aux);
2632       if (vec_safe_length (stridx_to_strinfo)
2633 	  && (*stridx_to_strinfo)[0] == (strinfo *) bb)
2634 	{
2635 	  unsigned int i;
2636 	  strinfo *si;
2637 
2638 	  for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
2639 	    free_strinfo (si);
2640 	  vec_free (stridx_to_strinfo);
2641 	}
2642       bb->aux = NULL;
2643     }
2644 }
2645 
2646 /* Main entry point.  */
2647 
2648 namespace {
2649 
2650 const pass_data pass_data_strlen =
2651 {
2652   GIMPLE_PASS, /* type */
2653   "strlen", /* name */
2654   OPTGROUP_NONE, /* optinfo_flags */
2655   TV_TREE_STRLEN, /* tv_id */
2656   ( PROP_cfg | PROP_ssa ), /* properties_required */
2657   0, /* properties_provided */
2658   0, /* properties_destroyed */
2659   0, /* todo_flags_start */
2660   0, /* todo_flags_finish */
2661 };
2662 
2663 class pass_strlen : public gimple_opt_pass
2664 {
2665 public:
2666   pass_strlen (gcc::context *ctxt)
2667     : gimple_opt_pass (pass_data_strlen, ctxt)
2668   {}
2669 
2670   /* opt_pass methods: */
2671   virtual bool gate (function *) { return flag_optimize_strlen != 0; }
2672   virtual unsigned int execute (function *);
2673 
2674 }; // class pass_strlen
2675 
2676 unsigned int
2677 pass_strlen::execute (function *fun)
2678 {
2679   ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
2680   max_stridx = 1;
2681 
2682   calculate_dominance_info (CDI_DOMINATORS);
2683 
2684   /* String length optimization is implemented as a walk of the dominator
2685      tree and a forward walk of statements within each block.  */
2686   strlen_dom_walker (CDI_DOMINATORS).walk (fun->cfg->x_entry_block_ptr);
2687 
2688   ssa_ver_to_stridx.release ();
2689   strinfo_pool.release ();
2690   if (decl_to_stridxlist_htab)
2691     {
2692       obstack_free (&stridx_obstack, NULL);
2693       delete decl_to_stridxlist_htab;
2694       decl_to_stridxlist_htab = NULL;
2695     }
2696   laststmt.stmt = NULL;
2697   laststmt.len = NULL_TREE;
2698   laststmt.stridx = 0;
2699 
2700   return 0;
2701 }
2702 
2703 } // anon namespace
2704 
2705 gimple_opt_pass *
2706 make_pass_strlen (gcc::context *ctxt)
2707 {
2708   return new pass_strlen (ctxt);
2709 }
2710