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.