https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127585
Bug ID: 127585
Summary: -ffuse-ops-with-volatile-access on m68k/coldfire
causes problem code generation
Product: gcc
Version: 16.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: gerg at polyxeno dot com
Target Milestone: ---
Created attachment 65675
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65675&action=edit
Pre-processed stand alone code fragment that can be compiled to show the
changed code generation.
A change in code generation when using "-ffuse-ops-with-volatile-access"
causes an 8bit byte access instead of 32bit access for a volatile pointer
de-reference on ColdFire/m68k in some circumstances. This can break access
to hardware device registers that only support 32bit accesses.
The problem pre-processed C code fragment looks like this:
typedef unsigned int uint;
typedef unsigned int u32;
__asm__ __volatile__("": : :"memory");
(ievent) = ({ u32 __v = (*( volatile u32 *) (fep->hwp + 0x004)); __v; });
if (ievent & ((uint)0x00800000)) {
___ret = 0;
break;
}
The generated code for this in gcc-16.2 is:
c: 45e8 0004 lea %a0@(4),%a2
10: 4a2a 0001 tstb %a2@(1)
14: 6b34 bmis 4a <fec_enet_mdio_wait+0x4a>
But with gcc-15 and older it was:
a: 2028 0004 movel %a0@(4),%d0
e: 0800 0017 btst #23,%d0
12: 6634 bnes 48 <fec_enet_mdio_wait+0x48>
Optimizing to a single byte access for the bit test means there
is no full 32bit access to the volatile address.
As expected compiling the kernel with "-fno-fuse-ops-with-volatile-access"
produces code identical to the old gcc behavior.
For reproducing purposes I have attached a C preprocessed file of the
code snippet from the kernel (func.c) that can be compiled stand alone
to demonstrate the changed asm code generation. Compile with:
m68k-uclinux-gcc -mcpu=5208 -O2 -c -o func.o func.c
I am using binutils-2.47, and gcc-16.2 both targeted for "m68k-uclinux".
The exact gcc configure line was:
./configure --target=m68k-uclinux \
--enable-multilib \
--disable-shared \
--disable-libssp \
--disable-threads \
--disable-libmudflap \
--disable-libgomp \
--disable-libatomic \
--disable-libsanitizer \
--disable-libquadmath \
--disable-libmpx \
--without-headers \
--with-system-zlib \
--enable-languages=c
The problem was found originally when compiling a linux kernel (in my case
linux-7.2) using gcc-16.2 for a ColdFire (m68k) target. Specifically the
problem is that the ethernet driver fails to probe with error:
fec fec.0 (unnamed net_device) (uninitialized): MDIO read timeout
When compiled with all older gcc versions prior to gcc-16 this works with
no probe error.
I bisected the problem to commit a6c50ec2c6eb ("Add
-ffuse-ops-with-volatile-access").