diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/gimple-ssa-store-merging.c | 131 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/store_merging_24.c | 75 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/store_merging_25.c | 75 |
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; +} |