Store-merging pass should run twice, the reason is pass fre/pre will do some kind of optimizations to instructions by: 1. Converting the load from address to load from function arguments (store_merging_30.c:foo1). 2. Converting the byte access to BIT_FIELD_REF(store_merging_30.c:foo2). 3. Other bitfield combinations or potential interference optimizations etc. These optimizations will break the store chain, store-merging pass fails to catch such kind of pattern so stores are not merged in middle end, then consecutive stb/sth instructions(should be merged to stw) are emitted finally.
And why not directly move store-merging pass(numbered 194) just before fre1(numbered 35) is for case store_merging_14.c, 5 merges are done by store_merging1, and 4 merges are done fore store_merge2. So, keep the original store_merge as store_merge2 as store merge may be still available after other pass optimizations. Most of the 30 store_merging_N.c test case dg-final pass name would be updated from store-merging to store-merging1 once this RFC patch idea got confirmed. Any comments? Thanks. PS: Before this patch, store_merging_30.c.035t.fre1: ... foo1: Inserted _13 = (short unsigned int) counters_new_5(D); Replaced tmp.D.2912.D.2911.D.2910.D.2909.inuse with _13 in all uses of _1 = tmp.D.2912.D.2911.D.2910.D.2909.inuse; Removing dead stmt _1 = tmp.D.2912.D.2911.D.2910.D.2909.inuse; ... foo2: Inserted _17 = BIT_FIELD_REF <_1, 8, 16>; Replaced tmp.D.2926.D.2925.D.2924.D.2923.objects with _17 in all uses of _3 = tmp.D.2926.D.2925.D.2924.D.2923.objects; Removing dead stmt _3 = tmp.D.2926.D.2925.D.2924.D.2923.objects; foo1 asm: rldicl 9,4,48,48 sth 4,0(3) sth 9,2(3) blr With this patch(similar for foo2): stw r4,0(r3) blr gcc/ChangeLog 2020-02-18 Xiong Hu Luo <luo...@linux.ibm.com> Part of PR middle-end/71509 gimple-ssa-store-merging.c (clone): New. passes.def (pass_store_merging): New. gcc/testsuite/ChangeLog 2020-02-18 Xiong Hu Luo <luo...@linux.ibm.com> Part of PR middle-end/71509 testsuite/gcc.dg/store_merging_14.c: Update. testsuite/gcc.dg/store_merging_30.c: New. --- gcc/gimple-ssa-store-merging.c | 2 + gcc/passes.def | 1 + gcc/testsuite/gcc.dg/store_merging_14.c | 3 +- gcc/testsuite/gcc.dg/store_merging_30.c | 86 +++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/store_merging_30.c diff --git a/gcc/gimple-ssa-store-merging.c b/gcc/gimple-ssa-store-merging.c index 8371323ef4a..9a5bd49fc3a 100644 --- a/gcc/gimple-ssa-store-merging.c +++ b/gcc/gimple-ssa-store-merging.c @@ -2156,6 +2156,8 @@ public: { } + opt_pass * clone () { return new pass_store_merging (m_ctxt); } + /* Pass not supported for PDP-endian, nor for insane hosts or target character sizes where native_{encode,interpret}_expr doesn't work properly. */ diff --git a/gcc/passes.def b/gcc/passes.def index 2bf2cb78fc5..e531531cb14 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -85,6 +85,7 @@ along with GCC; see the file COPYING3. If not see /* pass_build_ealias is a dummy pass that ensures that we execute TODO_rebuild_alias at this point. */ NEXT_PASS (pass_build_ealias); + NEXT_PASS (pass_store_merging); NEXT_PASS (pass_fre, true /* may_iterate */); NEXT_PASS (pass_early_vrp); NEXT_PASS (pass_merge_phi); diff --git a/gcc/testsuite/gcc.dg/store_merging_14.c b/gcc/testsuite/gcc.dg/store_merging_14.c index 9310aaf3489..bd120d18ac6 100644 --- a/gcc/testsuite/gcc.dg/store_merging_14.c +++ b/gcc/testsuite/gcc.dg/store_merging_14.c @@ -214,4 +214,5 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "Merging successful" 9 "store-merging" } } */ +/* { dg-final { scan-tree-dump-times "Merging successful" 5 "store-merging1" } } */ +/* { dg-final { scan-tree-dump-times "Merging successful" 4 "store-merging2" } } */ diff --git a/gcc/testsuite/gcc.dg/store_merging_30.c b/gcc/testsuite/gcc.dg/store_merging_30.c new file mode 100644 index 00000000000..71369c3b196 --- /dev/null +++ b/gcc/testsuite/gcc.dg/store_merging_30.c @@ -0,0 +1,86 @@ +/* { dg-do run } */ +/* { dg-require-effective-target store_merge } */ +/* { dg-options "-O2 -fdump-tree-store-merging" } */ + +typedef unsigned int atomic_t; + +struct page +{ + union + { + unsigned long counters; + struct + { + union + { + struct + { + unsigned inuse : 16; + unsigned objects : 15; + unsigned frozen : 1; + }; + }; + }; + }; +}; + +struct page2 +{ + union + { + unsigned counters; + struct + { + union + { + struct + { + unsigned inuse : 16; + unsigned objects : 8; + unsigned frozen : 8; + }; + }; + }; + }; +}; + +__attribute__((noipa)) void +foo1 (struct page *page, unsigned long counters_new) +{ + struct page tmp; + tmp.counters = counters_new; + page->inuse = tmp.inuse; + page->objects = tmp.objects; + page->frozen = tmp.frozen; +} + +__attribute__((noipa)) void +foo2 (struct page2 *page2, unsigned long counters_new) +{ + struct page2 tmp; + tmp.counters = counters_new; + page2->inuse = tmp.inuse; + page2->objects = tmp.objects; + page2->frozen = tmp.frozen; +} + +int main () +{ + struct page page; + foo1 (&page, 0x12345678ABCDEFFEUL); + + asm volatile ("" : : : "memory"); + if (page.frozen != 1 || page.objects != 0x2bcd || page.inuse != 0xeffe) + __builtin_abort (); + + struct page2 page2; + foo2 (&page2, 0x12345678ABCDEFFEUL); + + asm volatile ("" : : : "memory"); + + if (page2.frozen != 0xab || page2.objects != 0xcd || page2.inuse != 0xeffe) + __builtin_abort (); + return 0; +} + +/* { dg-final { scan-tree-dump-times "Merging successful" 2 "store-merging1" } } */ -- 2.21.0.777.g83232e3864