Commit 18e0c3d1 by Jakub Jelinek Committed by Jakub Jelinek

re PR tree-optimization/87859 (store-merging miscompilation of mesa)

	PR tree-optimization/87859
	* gimple-ssa-store-merging.c (struct merged_store_group): Add
	only_constants and first_nonmergeable_order members.
	(merged_store_group::merged_store_group): Initialize them.
	(merged_store_group::do_merge): Clear only_constants member if
	adding something other than INTEGER_CST store.
	(imm_store_chain_info::coalesce_immediate_stores): Don't merge
	stores with order >= first_nonmergeable_order.  Use
	merged_store->only_constants instead of always recomputing it.
	Set merged_store->first_nonmergeable_order if we've skipped any
	stores.  Attempt to merge overlapping INTEGER_CST stores that
	we would otherwise skip.

	* gcc.dg/store_merging_24.c: New test.
	* gcc.dg/store_merging_25.c: New test.

From-SVN: r265794
parent cbd42900
2018-11-05 Jakub Jelinek <jakub@redhat.com> 2018-11-05 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/87859
* gimple-ssa-store-merging.c (struct merged_store_group): Add
only_constants and first_nonmergeable_order members.
(merged_store_group::merged_store_group): Initialize them.
(merged_store_group::do_merge): Clear only_constants member if
adding something other than INTEGER_CST store.
(imm_store_chain_info::coalesce_immediate_stores): Don't merge
stores with order >= first_nonmergeable_order. Use
merged_store->only_constants instead of always recomputing it.
Set merged_store->first_nonmergeable_order if we've skipped any
stores. Attempt to merge overlapping INTEGER_CST stores that
we would otherwise skip.
PR sanitizer/87837 PR sanitizer/87837
* match.pd (X + Y < X): Don't optimize if TYPE_OVERFLOW_SANITIZED. * match.pd (X + Y < X): Don't optimize if TYPE_OVERFLOW_SANITIZED.
...@@ -1429,6 +1429,8 @@ struct merged_store_group ...@@ -1429,6 +1429,8 @@ struct merged_store_group
unsigned int first_order; unsigned int first_order;
unsigned int last_order; unsigned int last_order;
bool bit_insertion; bool bit_insertion;
bool only_constants;
unsigned int first_nonmergeable_order;
auto_vec<store_immediate_info *> stores; auto_vec<store_immediate_info *> stores;
/* We record the first and last original statements in the sequence because /* We record the first and last original statements in the sequence because
...@@ -1821,6 +1823,8 @@ merged_store_group::merged_store_group (store_immediate_info *info) ...@@ -1821,6 +1823,8 @@ merged_store_group::merged_store_group (store_immediate_info *info)
val = NULL; val = NULL;
mask = NULL; mask = NULL;
bit_insertion = false; bit_insertion = false;
only_constants = info->rhs_code == INTEGER_CST;
first_nonmergeable_order = ~0U;
unsigned HOST_WIDE_INT align_bitpos = 0; unsigned HOST_WIDE_INT align_bitpos = 0;
get_object_alignment_1 (gimple_assign_lhs (info->stmt), get_object_alignment_1 (gimple_assign_lhs (info->stmt),
&align, &align_bitpos); &align, &align_bitpos);
...@@ -1936,6 +1940,8 @@ merged_store_group::do_merge (store_immediate_info *info) ...@@ -1936,6 +1940,8 @@ merged_store_group::do_merge (store_immediate_info *info)
first_order = info->order; first_order = info->order;
first_stmt = stmt; first_stmt = stmt;
} }
if (info->rhs_code != INTEGER_CST)
only_constants = false;
} }
/* Merge a store recorded by INFO into this merged store. /* Merge a store recorded by INFO into this merged store.
...@@ -2696,32 +2702,25 @@ imm_store_chain_info::coalesce_immediate_stores () ...@@ -2696,32 +2702,25 @@ imm_store_chain_info::coalesce_immediate_stores ()
} }
} }
if (info->order >= merged_store->first_nonmergeable_order)
;
/* |---store 1---| /* |---store 1---|
|---store 2---| |---store 2---|
Overlapping stores. */ Overlapping stores. */
if (IN_RANGE (info->bitpos, merged_store->start, else if (IN_RANGE (info->bitpos, merged_store->start,
merged_store->start + merged_store->width - 1)) merged_store->start + merged_store->width - 1))
{ {
/* Only allow overlapping stores of constants. */ /* Only allow overlapping stores of constants. */
if (info->rhs_code == INTEGER_CST) if (info->rhs_code == INTEGER_CST && merged_store->only_constants)
{ {
bool only_constants = true;
store_immediate_info *infoj;
unsigned int j;
FOR_EACH_VEC_ELT (merged_store->stores, j, infoj)
if (infoj->rhs_code != INTEGER_CST)
{
only_constants = false;
break;
}
unsigned int last_order unsigned int last_order
= MAX (merged_store->last_order, info->order); = MAX (merged_store->last_order, info->order);
unsigned HOST_WIDE_INT end unsigned HOST_WIDE_INT end
= MAX (merged_store->start + merged_store->width, = MAX (merged_store->start + merged_store->width,
info->bitpos + info->bitsize); info->bitpos + info->bitsize);
if (only_constants if (check_no_overlap (m_store_info, i, INTEGER_CST,
&& check_no_overlap (m_store_info, i, INTEGER_CST, last_order, end))
last_order, end))
{ {
/* check_no_overlap call above made sure there are no /* check_no_overlap call above made sure there are no
overlapping stores with non-INTEGER_CST rhs_code overlapping stores with non-INTEGER_CST rhs_code
...@@ -2741,36 +2740,97 @@ imm_store_chain_info::coalesce_immediate_stores () ...@@ -2741,36 +2740,97 @@ imm_store_chain_info::coalesce_immediate_stores ()
store_by_bitpos order it comes after the last store that store_by_bitpos order it comes after the last store that
we can't merge with them. We can merge the first 3 stores we can't merge with them. We can merge the first 3 stores
and keep the last store as is though. */ and keep the last store as is though. */
unsigned int len = m_store_info.length (), k = i; unsigned int len = m_store_info.length ();
for (unsigned int j = i + 1; j < len; ++j) unsigned int try_order = last_order;
unsigned int first_nonmergeable_order;
unsigned int k;
bool last_iter = false;
int attempts = 0;
do
{ {
store_immediate_info *info2 = m_store_info[j]; unsigned int max_order = 0;
if (info2->bitpos >= end) unsigned first_nonmergeable_int_order = ~0U;
break; unsigned HOST_WIDE_INT this_end = end;
if (info2->order < last_order) k = i;
first_nonmergeable_order = ~0U;
for (unsigned int j = i + 1; j < len; ++j)
{ {
if (info2->rhs_code != INTEGER_CST) store_immediate_info *info2 = m_store_info[j];
if (info2->bitpos >= this_end)
break;
if (info2->order < try_order)
{
if (info2->rhs_code != INTEGER_CST)
{
/* Normally check_no_overlap makes sure this
doesn't happen, but if end grows below,
then we need to process more stores than
check_no_overlap verified. Example:
MEM[(int *)p_5] = 0;
MEM[(short *)p_5 + 3B] = 1;
MEM[(char *)p_5 + 4B] = _9;
MEM[(char *)p_5 + 2B] = 2; */
k = 0;
break;
}
k = j;
this_end = MAX (this_end,
info2->bitpos + info2->bitsize);
}
else if (info2->rhs_code == INTEGER_CST
&& !last_iter)
{ {
/* Normally check_no_overlap makes sure this max_order = MAX (max_order, info2->order + 1);
doesn't happen, but if end grows below, then first_nonmergeable_int_order
we need to process more stores than = MIN (first_nonmergeable_int_order,
check_no_overlap verified. Example: info2->order);
MEM[(int *)p_5] = 0;
MEM[(short *)p_5 + 3B] = 1;
MEM[(char *)p_5 + 4B] = _9;
MEM[(char *)p_5 + 2B] = 2; */
k = 0;
break;
} }
k = j; else
end = MAX (end, info2->bitpos + info2->bitsize); first_nonmergeable_order
= MIN (first_nonmergeable_order, info2->order);
}
if (k == 0)
{
if (last_order == try_order)
break;
/* If this failed, but only because we grew
try_order, retry with the last working one,
so that we merge at least something. */
try_order = last_order;
last_iter = true;
continue;
} }
last_order = try_order;
/* Retry with a larger try_order to see if we could
merge some further INTEGER_CST stores. */
if (max_order
&& (first_nonmergeable_int_order
< first_nonmergeable_order))
{
try_order = MIN (max_order,
first_nonmergeable_order);
try_order
= MIN (try_order,
merged_store->first_nonmergeable_order);
if (try_order > last_order && ++attempts < 16)
continue;
}
first_nonmergeable_order
= MIN (first_nonmergeable_order,
first_nonmergeable_int_order);
end = this_end;
break;
} }
while (1);
if (k != 0) if (k != 0)
{ {
merged_store->merge_overlapping (info); merged_store->merge_overlapping (info);
merged_store->first_nonmergeable_order
= MIN (merged_store->first_nonmergeable_order,
first_nonmergeable_order);
for (unsigned int j = i + 1; j <= k; j++) for (unsigned int j = i + 1; j <= k; j++)
{ {
store_immediate_info *info2 = m_store_info[j]; store_immediate_info *info2 = m_store_info[j];
...@@ -2778,7 +2838,8 @@ imm_store_chain_info::coalesce_immediate_stores () ...@@ -2778,7 +2838,8 @@ imm_store_chain_info::coalesce_immediate_stores ()
if (info2->order < last_order) if (info2->order < last_order)
{ {
gcc_assert (info2->rhs_code == INTEGER_CST); gcc_assert (info2->rhs_code == INTEGER_CST);
merged_store->merge_overlapping (info2); if (info != info2)
merged_store->merge_overlapping (info2);
} }
/* Other stores are kept and not merged in any /* Other stores are kept and not merged in any
way. */ way. */
......
2018-11-05 Jakub Jelinek <jakub@redhat.com> 2018-11-05 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/87859
* gcc.dg/store_merging_24.c: New test.
* gcc.dg/store_merging_25.c: New test.
PR sanitizer/87837 PR sanitizer/87837
* c-c++-common/ubsan/pr87837.c: New test. * c-c++-common/ubsan/pr87837.c: New test.
......
/* PR tree-optimization/87859 */
/* { dg-do run } */
/* { dg-options "-O2 -fdump-tree-store-merging-details" } */
/* { dg-final { scan-tree-dump "New sequence of \[23] stores to replace old one of 19 stores" "store-merging" { target i?86-*-* x86_64-*-* } } } */
/* { dg-final { scan-tree-dump "New sequence of 1 stores to replace old one of 6 stores" "store-merging" { target i?86-*-* x86_64-*-* } } } */
struct S {
union F {
struct T {
#define A(n) unsigned n:1;
#define B(n) A(n##0) A(n##1) A(n##2) A(n##3) A(n##4) \
A(n##5) A(n##6) A(n##7) A(n##8) A(n##9)
B(f) B(f1) B(f2) B(f3) B(f4) B(f5)
A(f60) A(f61) A(f62) A(f63) A(f64) A(f65) A(f66)
} q;
unsigned int i[3];
} f;
};
struct S s = {
.f.q.f0 = 1, .f.q.f1 = 1, .f.q.f2 = 1, .f.q.f5 = 1, .f.q.f6 = 1,
.f.q.f7 = 1, .f.q.f8 = 1, .f.q.f9 = 1, .f.q.f13 = 1, .f.q.f14 = 1,
.f.q.f15 = 1, .f.q.f16 = 1, .f.q.f17 = 1, .f.q.f19 = 1, .f.q.f21 = 1,
.f.q.f66 = 1
};
__attribute__((noipa)) void
bar (unsigned *x)
{
if (x[0] != s.f.i[0] || x[1] != s.f.i[1] || x[2] != s.f.i[2])
__builtin_abort ();
}
__attribute__((noipa)) void
foo (unsigned char *state)
{
struct S i;
i.f.i[0] = 0;
i.f.i[1] = 0;
i.f.i[2] = 0;
i.f.q.f7 = 1;
i.f.q.f2 = 1;
i.f.q.f21 = 1;
i.f.q.f19 = 1;
i.f.q.f14 = 1;
i.f.q.f5 = 1;
i.f.q.f0 = 1;
i.f.q.f15 = 1;
i.f.q.f16 = 1;
i.f.q.f6 = 1;
i.f.q.f9 = 1;
i.f.q.f17 = 1;
i.f.q.f1 = 1;
i.f.q.f8 = 1;
i.f.q.f13 = 1;
i.f.q.f66 = 1;
if (*state)
{
i.f.q.f37 = 1;
i.f.q.f38 = 1;
i.f.q.f39 = 1;
i.f.q.f40 = 1;
i.f.q.f41 = 1;
i.f.q.f36 = 1;
}
bar (i.f.i);
}
int
main ()
{
unsigned char z = 0;
foo (&z);
return 0;
}
/* PR tree-optimization/87859 */
/* { dg-do run } */
/* { dg-options "-O2 -fdump-tree-store-merging-details" } */
/* { dg-final { scan-tree-dump "New sequence of \[23] stores to replace old one of 14 stores" "store-merging" { target i?86-*-* x86_64-*-* } } } */
/* { dg-final { scan-tree-dump "New sequence of 1 stores to replace old one of 6 stores" "store-merging" { target i?86-*-* x86_64-*-* } } } */
struct S {
union F {
struct T {
#define A(n) unsigned n:1;
#define B(n) A(n##0) A(n##1) A(n##2) A(n##3) A(n##4) \
A(n##5) A(n##6) A(n##7) A(n##8) A(n##9)
B(f) B(f1) B(f2) B(f3) B(f4) B(f5)
A(f60) A(f61) A(f62) A(f63) A(f64) A(f65) A(f66)
} q;
unsigned int i[3];
} f;
};
struct S s = {
.f.q.f0 = 1, .f.q.f1 = 1, .f.q.f2 = 1, .f.q.f5 = 1, .f.q.f6 = 1,
.f.q.f7 = 1, .f.q.f8 = 1, .f.q.f9 = 1, .f.q.f13 = 1, .f.q.f14 = 1,
.f.q.f15 = 1, .f.q.f16 = 1, .f.q.f17 = 1, .f.q.f19 = 1, .f.q.f21 = 1,
.f.q.f66 = 1
};
__attribute__((noipa)) void
bar (unsigned *x)
{
if (x[0] != s.f.i[0] || x[1] != s.f.i[1] || x[2] != s.f.i[2])
__builtin_abort ();
}
__attribute__((noipa)) void
foo (unsigned char *state, unsigned char c)
{
struct S i;
i.f.i[0] = 0;
i.f.i[1] = 0;
i.f.i[2] = 0;
i.f.q.f7 = 1;
i.f.q.f2 = 1;
i.f.q.f21 = 1;
i.f.q.f19 = 1;
i.f.q.f14 = 1;
i.f.q.f5 = 1;
i.f.q.f0 = 1;
i.f.q.f15 = 1;
i.f.q.f16 = 1;
i.f.q.f6 = 1;
i.f.q.f9 = 1;
i.f.q.f17 = c;
i.f.q.f1 = 1;
i.f.q.f8 = 1;
i.f.q.f13 = 1;
i.f.q.f66 = 1;
if (*state)
{
i.f.q.f37 = 1;
i.f.q.f38 = 1;
i.f.q.f39 = 1;
i.f.q.f40 = 1;
i.f.q.f41 = 1;
i.f.q.f36 = 1;
}
bar (i.f.i);
}
int
main ()
{
unsigned char z = 0;
foo (&z, 1);
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment