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
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);
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.
}
}
+ 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
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];
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. */
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}