[Bug middle-end/126552] New: const-qualified local register variable used as an asm operand is silently discarded

bernie at codewiz dot org via Gcc-bugs <[email protected]>
Newsgroups gmane.comp.gcc.bugs
Message-ID <[email protected]/bugzilla/>
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126552

            Bug ID: 126552
           Summary: const-qualified local register variable used as an asm
                    operand is silently discarded
           Product: gcc
           Version: 16.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: middle-end
          Assignee: unassigned at gcc dot gnu.org
          Reporter: bernie at codewiz dot org
  Target Milestone: ---

Created attachment 65196
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65196&action=edit
repro testcase

The attached testcase a0-repro.c mimics the expansion of NDK macros used when
calling AmigaOS dynamic library functions which take arguments in specified
m68k registers.

Godbolt playground: https://godbolt.org/z/36aszb4ox

A library call like this:

  BltPattern(rp, NULL, xmin, ymin, xmax, ymax, mask);

Expands to:

  {
    struct RastPort *_v1 = rp;
    const PLANEPTR _v2 = 0L;
    register int _d0 __asm("d0");
    register int _d1 __asm("d1");
    register struct RastPort *_n1 __asm("a1") = _v1;
    register const PLANEPTR _n2 __asm("a0") = _v2;  // VANISHES!
    register void *const _bn __asm("a6") = GfxBase;

    __asm volatile("jsr %%a6@(-0x138:W)"
                   : "=r"(_d0), "=r"(_d1)
                   : "r"(_bn), "rf"(_n1), "rf"(_n2)
                   : "fp0", "fp1", "cc", "memory");
  }

Compiled for m68k at -O1 and above, the const case never writes A0:

  call_const:
        move.l %a6,-(%sp)
        move.l 8(%sp),%a1
        move.l GfxBase,%a6
        clr.l %d0           // Did you mean A0?
        jsr %a6@(-0x138:W)
        move.l (%sp)+,%a6
        rts

  call_const_nonconst_var:
        move.l %a6,-(%sp)
        move.l 8(%sp),%a1
        sub.l %a0,%a0       // OK
        move.l GfxBase,%a6
        jsr %a6@(-0x138:W)
        move.l (%sp)+,%a6
        rts


This affects GCC versions 13.4 through 16.1. GCC 6.5.0 clears A0 in both cases,
at any optimization level.

The manual documents that a const-qualified local register variable may have
its initializer substituted into an asm statement, causing the operand to
appear in a different register:

  https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html

That may be what happens above, but it happens silently: the operand is placed
in
a register the programmer did not ask for, and nothing is diagnosed at any
warning level.

That could be a legitimate use of the latitude the docs reserve, so this is
primarily filed as a request for a warning, not as wrong code.

A diagnostic matters because the AmigaOS NDK inline headers generate exactly
this construct for every library call, takeing the type of the register
variable from a const-qualified parameter:

  register const PLANEPTR _n2 __asm("a0") = _v2;

Every such call passing a NULL pointer therefore passes whatever A0 happened to
hold, leading to memory corruption and very unpleasant debugging sessions.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.