[Bug inline-asm/57299] New: Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures

umbricola at gmail dot com gcc-bugzilla@gcc.gnu.org
Wed May 15 18:08:00 GMT 2013


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57299

            Bug ID: 57299
           Summary: Inline assembly memory dependencies produce spurious
                    loads, register pressure, compilation failures
           Product: gcc
           Version: 4.8.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: inline-asm
          Assignee: unassigned at gcc dot gnu.org
          Reporter: umbricola at gmail dot com

Consider this function with an inline assembly statement that takes two pointer
inputs in named registers and declares that it reads and writes the memory they
point to.

void f(char *x, char *y) {
  register char *p asm("edi") = x;
  register char *q asm("esi") = y;
  asm(""
      : "=m" (*x), "=m" (*y)
      : "r" (p), "r" (q), "m" (*x), "m" (*y));
}

This function should compile cleanly, and the disassembly should have only the
two instructions to load edi and esi from the stacked function arguments,
preceded by the prologue of f() and followed by the epilogue of f().

In fact this function is rejected by gcc -m32 -fPIC -c -o f.o f.c:

f.c: In function ‘f’:
f.c:4:3: error: ‘asm’ operand has impossible constraints
   asm(""
   ^

This error is wrong.  I am using only two named registers, neither of which is
ebx (which is reserved for the implementation of PIC).  There are three
general-purpose registers left, not to mention that loading edi and esi from
the stack shouldn't need any scratch registers anyway.

More strangely, removing any one or more of the four memory inputs and outputs
causes the function to compile successfully.  Memory dependencies should not
have any effect on register bindings entering and leaving the inline assembly
statement, only on optimizations in surrounding code.  Removing the -fPIC
option (which frees ebx) also makes the function compile.

If I remove one of the memory dependencies and disassemble the generated object
code, I see the two expected loads to edi and esi from the stack followed by
three unexpected loads to eax, ecx, and edx from the stack.  If I leave all the
memory dependencies and remove -fPIC instead, then all four of eax, ebx, ecx,
and edx get loaded after the asm statement.

It appears that gcc can convert memory dependencies of inline assembly
statements into useless loads into unrelated general-purpose registers.  This
action is always inefficient and sometimes spuriously exhausts the
general-purpose registers, causing valid code to be rejected.

I am running a 64-bit gcc 4.8.0 that I compiled from sources.  gcc -v says:

Using built-in specs.
COLLECT_GCC=/home/cmihelic/gcc-4.8.0/install/bin/gcc
COLLECT_LTO_WRAPPER=/home/cmihelic/gcc-4.8.0/install/libexec/gcc/x86_64-unknown-linux-gnu/4.8.0/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: ./configure --prefix=/home/cmihelic/gcc-4.8.0/install
Thread model: posix
gcc version 4.8.0 (GCC) 

On a different Linux machine I have also tried several 64-bit gcc installations
I did not compile myself: versions 4.7.2, 4.5.0, 4.4.5, 4.4.3, 4.1.2, and
3.3.1.  They fail similarly, although the error message used to be

f.c:4: error: can't find a register in class `GENERAL_REGS' while reloading
`asm'

Thus this behavior is at least ten years old.


More information about the Gcc-bugs mailing list