https://gcc.gnu.org/bugzilla/show_bug.cgi?id=18041
--- Comment #8 from Richard Biener <rguenth at gcc dot gnu.org> --- We're still "stuck" on GIMPLE, on x86_64 we manage to elide the redundant load now and get foo: .LFB0: .cfi_startproc movzbl (%rdi), %eax movl %eax, %edx shrb %dl orl %eax, %edx andl $-2, %eax andl $1, %edx orl %edx, %eax movb %al, (%rdi) ret where we fail to notice the RMW. A simpler testcase is struct B { unsigned bit0 : 1; }; void bar (struct B *b, _Bool x) { b->bit0 |= x; } which generates bar: .LFB0: .cfi_startproc movzbl (%rdi), %eax orl %eax, %esi andl $-2, %eax andl $1, %esi orl %esi, %eax movb %al, (%rdi) ret we'd need to recognize (set (reg:QI 96) (ior:QI (and:QI (reg:QI 90 [ *b_3(D) ]) (const_int -2 [0xfffffffffffffffe]))) (and:QI (ior:QI (reg:QI 90 [ *b_3(D) ]) (subreg:QI (reg:SI 98) 0)) (const_int 1 [0x1])))) (r90 & -2) | ((r90 | rx) & 1) -> (r90 & -2) | (r90 & 1) | (rx & 1) -> r90 | (rx & 1) I have a patch for simplify-rtx.c that recognizes this generating foo: .LFB0: .cfi_startproc movzbl (%rdi), %edx movl %edx, %eax shrb %al andl $1, %eax orl %edx, %eax movb %al, (%rdi) ret and bar: .LFB1: .cfi_startproc andl $1, %esi orb %sil, (%rdi) ret