OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [tree-ssa-strlen.c] - Blame information for rev 818

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
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
};

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.