https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86844
Bug ID: 86844 Summary: wrong code generation cause by store merging pass Product: gcc Version: 8.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: tree-optimization Assignee: unassigned at gcc dot gnu.org Reporter: krebbel at gcc dot gnu.org Target Milestone: --- Created attachment 44502 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=44502&action=edit Reduced testcase Compiling the attached testcase with -O2 results in the following code: movzbl 4(%rdi), %eax movl $33024, 8(%rdi) movb %al, 10(%rdi) 33024 -> 0 0 129 0 The store of 222 gets optimized away. Without store merging: movzbl 4(%rdi), %eax movl $0, 8(%rdi) movb $-34, 11(%rdi) movb $-127, 9(%rdi) movb %al, 10(%rdi) The original order of stores: a->b.wd0.u4i = 0; a->b.wd0.s2.w = 222; a->b.wd0.s2.y = 129; a->b.wd0.s2.z = a->f.wd1.s2.z; coalesce_immediate_stores first reorders the stores according to its bit positions: a->b.wd0.u4i = 0; a->b.wd0.s2.y = 129; a->b.wd0.s2.z = a->f.wd1.s2.z; a->b.wd0.s2.w = 222; It then merges the first and the second and has to end the group seeing the third. So the last ends up in its own group. Emitting the stores in the original order makes the 222 store dead. The first two should not be merged. coalesce_immediate_stores already tries to detect cases where stores later in the chain might get invalidated by merging early stores but it also assumes that if the later store also stores a constant it will be possible to merge it as well. However, in this case the non-constant store in between prevents this. Store merging pass output: ;; Function f (f, funcdef_no=0, decl_uid=1922, cgraph_uid=1, symbol_order=0) Processing basic block <2>: Starting new chain with statement: a_3(D)->b.wd0.u4i = 0; The base object is: a_3(D) Recording immediate store from stmt: a_3(D)->b.wd0.s2.w = 222; Recording immediate store from stmt: a_3(D)->b.wd0.s2.y = 129; Recording immediate store from stmt: a_3(D)->b.wd0.s2.z = _1; stmt causes chain termination: return; Attempting to coalesce 4 stores in chain New store group Store 0: bitsize:32 bitpos:64 val:0 Store 1: bitsize:8 bitpos:72 val:129 After writing 0 of size 32 at position 0 the merged value contains 00 00 00 00 the merged mask contains 00 00 00 00 After writing 129 of size 8 at position 8 the merged value contains 00 81 00 00 the merged mask contains 00 00 00 00 New store group Store 2: bitsize:8 bitpos:80 val:_1 New store group Store 3: bitsize:8 bitpos:88 val:222 Coalescing successful! Merged into 1 stores New sequence of 1 stores to replace old one of 2 stores # .MEM_6 = VDEF <.MEM_5> MEM[(union *)a_3(D) + 8B] = 33024; Merging successful! f (struct bar * a) { unsigned char _1; <bb 2> [local count: 1073741825]: a_3(D)->b.wd0.s2.w = 222; MEM[(union *)a_3(D) + 8B] = 33024; _1 = a_3(D)->D.1919.f.wd1.s2.z; a_3(D)->b.wd0.s2.z = _1; return; }