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