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").

Reply via email to