aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/gimple-ssa-store-merging.c131
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/store_merging_24.c75
-rw-r--r--gcc/testsuite/gcc.dg/store_merging_25.c75
5 files changed, 263 insertions, 35 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 099b540..7e7fd22 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,18 @@
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
* match.pd (X + Y < X): Don't optimize if TYPE_OVERFLOW_SANITIZED.
diff --git a/gcc/gimple-ssa-store-merging.c b/gcc/gimple-ssa-store-merging.c
index 5e5823c..e813e45 100644
--- a/gcc/gimple-ssa-store-merging.c
+++ b/gcc/gimple-ssa-store-merging.c
@@ -1429,6 +1429,8 @@ struct merged_store_group
unsigned int first_order;
unsigned int last_order;
bool bit_insertion;
+ bool only_constants;
+ unsigned int first_nonmergeable_order;
auto_vec<store_immediate_info *> stores;
/* 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)
val = NULL;
mask = NULL;
bit_insertion = false;
+ only_constants = info->rhs_code == INTEGER_CST;
+ first_nonmergeable_order = ~0U;
unsigned HOST_WIDE_INT align_bitpos = 0;
get_object_alignment_1 (gimple_assign_lhs (info->stmt),
&align, &align_bitpos);
@@ -1936,6 +1940,8 @@ merged_store_group::do_merge (store_immediate_info *info)
first_order = info->order;
first_stmt = stmt;
}
+ if (info->rhs_code != INTEGER_CST)
+ only_constants = false;
}
/* Merge a store recorded by INFO into this merged store.
@@ -2696,32 +2702,25 @@ imm_store_chain_info::coalesce_immediate_stores ()
}
}
+ if (info->order >= merged_store->first_nonmergeable_order)
+ ;
+
/* |---store 1---|
|---store 2---|
Overlapping stores. */
- if (IN_RANGE (info->bitpos, merged_store->start,
- merged_store->start + merged_store->width - 1))
+ else if (IN_RANGE (info->bitpos, merged_store->start,
+ merged_store->start + merged_store->width - 1))
{
/* 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
= MAX (merged_store->last_order, info->order);
unsigned HOST_WIDE_INT end
= MAX (merged_store->start + merged_store->width,
info->bitpos + info->bitsize);
- if (only_constants
- && check_no_overlap (m_store_info, i, INTEGER_CST,
- last_order, end))
+ if (check_no_overlap (m_store_info, i, INTEGER_CST,
+ last_order, end))
{
/* check_no_overlap call above made sure there are no
overlapping stores with non-INTEGER_CST rhs_code
@@ -2741,36 +2740,97 @@ imm_store_chain_info::coalesce_immediate_stores ()
store_by_bitpos order it comes after the last store that
we can't merge with them. We can merge the first 3 stores
and keep the last store as is though. */
- unsigned int len = m_store_info.length (), k = i;
- for (unsigned int j = i + 1; j < len; ++j)
+ unsigned int len = m_store_info.length ();
+ 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];
- if (info2->bitpos >= end)
- break;
- if (info2->order < last_order)
+ unsigned int max_order = 0;
+ unsigned first_nonmergeable_int_order = ~0U;
+ unsigned HOST_WIDE_INT this_end = end;
+ 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
- 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;
+ max_order = MAX (max_order, info2->order + 1);
+ first_nonmergeable_int_order
+ = MIN (first_nonmergeable_int_order,
+ info2->order);
}
- k = j;
- end = MAX (end, info2->bitpos + info2->bitsize);
+ else
+ 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)
{
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++)
{
store_immediate_info *info2 = m_store_info[j];
@@ -2778,7 +2838,8 @@ imm_store_chain_info::coalesce_immediate_stores ()
if (info2->order < last_order)
{
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
way. */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 0bb7b76..712f513 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,9 @@
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
* c-c++-common/ubsan/pr87837.c: New test.
diff --git a/gcc/testsuite/gcc.dg/store_merging_24.c b/gcc/testsuite/gcc.dg/store_merging_24.c
new file mode 100644
index 0000000..744fe60
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/store_merging_24.c
@@ -0,0 +1,75 @@
+/* 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;
+}
diff --git a/gcc/testsuite/gcc.dg/store_merging_25.c b/gcc/testsuite/gcc.dg/store_merging_25.c
new file mode 100644
index 0000000..cf18219
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/store_merging_25.c
@@ -0,0 +1,75 @@
+/* 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;
+}