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