re PR tree-optimization/79090 (DSE wrongly removes store at variable offset)
2017-01-16 Jeff Law <law@redhat.com> PR tree-optimization/79090 PR tree-optimization/33562 PR tree-optimization/61912 PR tree-optimization/77485 * tree-ssa-dse.c (compute_trims): Accept STMT argument. Dump STMT and computed trims into the dump file. PR tree-optimization/79090 PR tree-optimization/33562 PR tree-optimization/61912 PR tree-optimization/77485 * tree-ssa-dse.c (compute_trims): Accept STMT argument. Dump STMT and computed trims into the dump file. From-SVN: r244509
This commit is contained in:
parent
af995bf019
commit
a59afbe2fe
|
@ -1,3 +1,12 @@
|
|||
2017-01-16 Jeff Law <law@redhat.com>
|
||||
|
||||
PR tree-optimization/79090
|
||||
PR tree-optimization/33562
|
||||
PR tree-optimization/61912
|
||||
PR tree-optimization/77485
|
||||
* tree-ssa-dse.c (compute_trims): Accept STMT argument. Dump STMT
|
||||
and computed trims into the dump file.
|
||||
|
||||
2017-01-17 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
* config/i386/i386.h (LIMIT_RELOAD_CLASS): Remove.
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
2017-01-16 Jeff Law <law@redhat.com>
|
||||
|
||||
PR tree-optimization/33562
|
||||
PR tree-optimization/61912
|
||||
PR tree-optimization/77485
|
||||
PR tree-optimization/79090
|
||||
* gcc.dg/tree-ssa/ssa-dse-29.c: New test.
|
||||
* g++.dg/tree-ssa/ssa-dse-2.C: New test.
|
||||
|
||||
2017-01-16 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c/79089
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-dse2-details" } */
|
||||
|
||||
typedef long unsigned int size_t;
|
||||
extern "C"
|
||||
{
|
||||
extern void *memmove (void *__dest, const void *__src, size_t __n) throw ()
|
||||
__attribute__ ((__nonnull__ (1, 2)));
|
||||
}
|
||||
extern void abort () __attribute__ ((__noreturn__));
|
||||
struct vec_prefix { unsigned m_num; };
|
||||
struct vl_embed { };
|
||||
struct vl_ptr { };
|
||||
struct va_heap { typedef vl_ptr default_layout; };
|
||||
template < typename T, typename A = va_heap, typename L = typename A::default_layout > struct vec { };
|
||||
template < typename T, typename A > struct vec < T, A, vl_embed >
|
||||
{
|
||||
unsigned length (void) const { return m_vecpfx. m_num; }
|
||||
bool is_empty (void) const { return m_vecpfx. m_num == 0; }
|
||||
void block_remove (unsigned, unsigned);
|
||||
vec_prefix m_vecpfx;
|
||||
T m_vecdata[1];
|
||||
};
|
||||
template < typename T, typename A > inline void vec < T, A, vl_embed >::block_remove (unsigned ix, unsigned len)
|
||||
{
|
||||
T * slot = &m_vecdata[ix];
|
||||
m_vecpfx.m_num -= len;
|
||||
memmove (slot, slot + len, (m_vecpfx.m_num - ix) * sizeof (T));
|
||||
}
|
||||
|
||||
template < typename T > struct vec < T, va_heap, vl_ptr >
|
||||
{
|
||||
bool is_empty (void) const { return m_vec ? m_vec-> is_empty () : true; }
|
||||
unsigned length (void) const { return m_vec ? m_vec-> length () : 0; }
|
||||
void block_remove (unsigned, unsigned);
|
||||
vec < T, va_heap, vl_embed > * m_vec;
|
||||
};
|
||||
template < typename T > inline void vec < T, va_heap, vl_ptr >::block_remove (unsigned ix, unsigned len)
|
||||
{
|
||||
m_vec->block_remove (ix, len);
|
||||
}
|
||||
|
||||
typedef struct _list_node * _list_t;
|
||||
typedef struct _expr expr_def;
|
||||
typedef expr_def * expr_t;
|
||||
typedef _list_t av_set_t;
|
||||
static vec < expr_t > vec_av_set;
|
||||
bool
|
||||
fill_vec_av_set (av_set_t av)
|
||||
{
|
||||
if (vec_av_set.length () > 0)
|
||||
vec_av_set.block_remove (0, vec_av_set.length ());
|
||||
((!(vec_av_set.is_empty ())? abort () , 0 : 0));
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-not "Trimming statement .head = -" "dse2" } } */
|
||||
/* { dg-final { scan-tree-dump "Deleted dead call: " "dse2" } } */
|
||||
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-dse-details" } */
|
||||
|
||||
struct z {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
};
|
||||
|
||||
int
|
||||
foo(int cond, struct z *s)
|
||||
{
|
||||
|
||||
if (cond)
|
||||
{
|
||||
s->a = 1;
|
||||
s->b = 2;
|
||||
s->c = 3;
|
||||
}
|
||||
__builtin_memset (s, 0, sizeof (struct z));
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "Deleted dead store" 3 "dse1"} } */
|
||||
/* { dg-final { scan-tree-dump-not "Deleted dead store" "dse2"} } */
|
||||
/* { dg-final { scan-tree-dump-not "Deleted dead store" "dse3"} } */
|
||||
|
|
@ -212,10 +212,14 @@ setup_live_bytes_from_ref (ao_ref *ref, sbitmap live_bytes)
|
|||
tail of ORIG resulting in a bitmap that is a superset of LIVE.
|
||||
|
||||
Store the number of elements trimmed from the head and tail in
|
||||
TRIM_HEAD and TRIM_TAIL. */
|
||||
TRIM_HEAD and TRIM_TAIL.
|
||||
|
||||
STMT is the statement being trimmed and is used for debugging dump
|
||||
output only. */
|
||||
|
||||
static void
|
||||
compute_trims (ao_ref *ref, sbitmap live, int *trim_head, int *trim_tail)
|
||||
compute_trims (ao_ref *ref, sbitmap live, int *trim_head, int *trim_tail,
|
||||
gimple *stmt)
|
||||
{
|
||||
/* We use sbitmaps biased such that ref->offset is bit zero and the bitmap
|
||||
extends through ref->size. So we know that in the original bitmap
|
||||
|
@ -231,6 +235,15 @@ compute_trims (ao_ref *ref, sbitmap live, int *trim_head, int *trim_tail)
|
|||
int first_orig = 0;
|
||||
int first_live = bitmap_first_set_bit (live);
|
||||
*trim_head = (first_live - first_orig) & ~0x1;
|
||||
|
||||
if ((*trim_head || *trim_tail)
|
||||
&& dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, " Trimming statement (head = %d, tail = %d): ",
|
||||
*trim_head, *trim_tail);
|
||||
print_gimple_stmt (dump_file, stmt, dump_flags, 0);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* STMT initializes an object from COMPLEX_CST where one or more of the
|
||||
|
@ -244,7 +257,7 @@ static void
|
|||
maybe_trim_complex_store (ao_ref *ref, sbitmap live, gimple *stmt)
|
||||
{
|
||||
int trim_head, trim_tail;
|
||||
compute_trims (ref, live, &trim_head, &trim_tail);
|
||||
compute_trims (ref, live, &trim_head, &trim_tail, stmt);
|
||||
|
||||
/* The amount of data trimmed from the head or tail must be at
|
||||
least half the size of the object to ensure we're trimming
|
||||
|
@ -296,7 +309,7 @@ maybe_trim_constructor_store (ao_ref *ref, sbitmap live, gimple *stmt)
|
|||
|
||||
int head_trim = 0;
|
||||
int tail_trim = 0;
|
||||
compute_trims (ref, live, &head_trim, &tail_trim);
|
||||
compute_trims (ref, live, &head_trim, &tail_trim, stmt);
|
||||
|
||||
/* Now we want to replace the constructor initializer
|
||||
with memset (object + head_trim, 0, size - head_trim - tail_trim). */
|
||||
|
@ -384,7 +397,7 @@ maybe_trim_memstar_call (ao_ref *ref, sbitmap live, gimple *stmt)
|
|||
case BUILT_IN_MEMMOVE:
|
||||
{
|
||||
int head_trim, tail_trim;
|
||||
compute_trims (ref, live, &head_trim, &tail_trim);
|
||||
compute_trims (ref, live, &head_trim, &tail_trim, stmt);
|
||||
|
||||
/* Tail trimming is easy, we can just reduce the count. */
|
||||
if (tail_trim)
|
||||
|
@ -405,7 +418,7 @@ maybe_trim_memstar_call (ao_ref *ref, sbitmap live, gimple *stmt)
|
|||
case BUILT_IN_MEMSET:
|
||||
{
|
||||
int head_trim, tail_trim;
|
||||
compute_trims (ref, live, &head_trim, &tail_trim);
|
||||
compute_trims (ref, live, &head_trim, &tail_trim, stmt);
|
||||
|
||||
/* Tail trimming is easy, we can just reduce the count. */
|
||||
if (tail_trim)
|
||||
|
|
Loading…
Reference in New Issue