OSDN Git Service

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