public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug inline-asm/57299] New: Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures
@ 2013-05-15 18:08 umbricola at gmail dot com
  2013-05-15 18:14 ` [Bug inline-asm/57299] " pinskia at gcc dot gnu.org
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: umbricola at gmail dot com @ 2013-05-15 18:08 UTC (permalink / raw)
  To: gcc-bugs

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.
>From gcc-bugs-return-422385-listarch-gcc-bugs=gcc.gnu.org@gcc.gnu.org Wed May 15 18:11:06 2013
Return-Path: <gcc-bugs-return-422385-listarch-gcc-bugs=gcc.gnu.org@gcc.gnu.org>
Delivered-To: listarch-gcc-bugs@gcc.gnu.org
Received: (qmail 8204 invoked by alias); 15 May 2013 18:11:06 -0000
Mailing-List: contact gcc-bugs-help@gcc.gnu.org; run by ezmlm
Precedence: bulk
List-Id: <gcc-bugs.gcc.gnu.org>
List-Archive: <http://gcc.gnu.org/ml/gcc-bugs/>
List-Post: <mailto:gcc-bugs@gcc.gnu.org>
List-Help: <mailto:gcc-bugs-help@gcc.gnu.org>
Sender: gcc-bugs-owner@gcc.gnu.org
Delivered-To: mailing list gcc-bugs@gcc.gnu.org
Received: (qmail 8149 invoked by uid 48); 15 May 2013 18:11:02 -0000
From: "pinskia at gcc dot gnu.org" <gcc-bugzilla@gcc.gnu.org>
To: gcc-bugs@gcc.gnu.org
Subject: [Bug middle-end/57287] GCC 4.9.0 fails to build GDB on Ubuntu 12.04
Date: Wed, 15 May 2013 18:11:00 -0000
X-Bugzilla-Reason: CC
X-Bugzilla-Type: changed
X-Bugzilla-Watch-Reason: None
X-Bugzilla-Product: gcc
X-Bugzilla-Component: middle-end
X-Bugzilla-Version: 4.9.0
X-Bugzilla-Keywords:
X-Bugzilla-Severity: normal
X-Bugzilla-Who: pinskia at gcc dot gnu.org
X-Bugzilla-Status: WAITING
X-Bugzilla-Priority: P3
X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org
X-Bugzilla-Target-Milestone: ---
X-Bugzilla-Flags:
X-Bugzilla-Changed-Fields: component bug_severity
Message-ID: <bug-57287-4-fOWAIyssf6@http.gcc.gnu.org/bugzilla/>
In-Reply-To: <bug-57287-4@http.gcc.gnu.org/bugzilla/>
References: <bug-57287-4@http.gcc.gnu.org/bugzilla/>
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: 7bit
X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/
Auto-Submitted: auto-generated
MIME-Version: 1.0
X-SW-Source: 2013-05/txt/msg01058.txt.bz2
Content-length: 353

http://gcc.gnu.org/bugzilla/show_bug.cgi?idW287

Andrew Pinski <pinskia at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
          Component|c                           |middle-end
           Severity|blocker                     |normal


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Bug inline-asm/57299] Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures
  2013-05-15 18:08 [Bug inline-asm/57299] New: Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures umbricola at gmail dot com
@ 2013-05-15 18:14 ` pinskia at gcc dot gnu.org
  2013-05-15 18:22 ` umbricola at gmail dot com
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: pinskia at gcc dot gnu.org @ 2013-05-15 18:14 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #1 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
I think you are wrong in how many registers that inline-asm uses.  It uses 4
registers, two each to hold y and x which have to be loaded into a register
from the stack.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Bug inline-asm/57299] Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures
  2013-05-15 18:08 [Bug inline-asm/57299] New: Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures umbricola at gmail dot com
  2013-05-15 18:14 ` [Bug inline-asm/57299] " pinskia at gcc dot gnu.org
@ 2013-05-15 18:22 ` umbricola at gmail dot com
  2013-05-15 18:24 ` pinskia at gcc dot gnu.org
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: umbricola at gmail dot com @ 2013-05-15 18:22 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #2 from Chris Mihelich <umbricola at gmail dot com> ---
The asm statement uses only two registers.  Of the six inputs and outputs, only
"r" (p) and "r" (q) are registers; the four "=m" and "m" entries only declare
that memory is read or written in the assembly code.  See the part of
http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html about memory operands
(search for "If your assembler instructions access memory").


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Bug inline-asm/57299] Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures
  2013-05-15 18:08 [Bug inline-asm/57299] New: Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures umbricola at gmail dot com
  2013-05-15 18:14 ` [Bug inline-asm/57299] " pinskia at gcc dot gnu.org
  2013-05-15 18:22 ` umbricola at gmail dot com
@ 2013-05-15 18:24 ` pinskia at gcc dot gnu.org
  2013-05-15 18:44 ` umbricola at gmail dot com
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: pinskia at gcc dot gnu.org @ 2013-05-15 18:24 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #3 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
(In reply to Chris Mihelich from comment #2)
> The asm statement uses only two registers.  Of the six inputs and outputs,
> only "r" (p) and "r" (q) are registers; the four "=m" and "m" entries only
> declare that memory is read or written in the assembly code.  See the part
> of http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html about memory operands
> (search for "If your assembler instructions access memory").

Since the value of y and x are stored on the stack as they are arguments to the
function, their values need to be loaded into a regsiter first before passing
it on to the inline-asm.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Bug inline-asm/57299] Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures
  2013-05-15 18:08 [Bug inline-asm/57299] New: Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures umbricola at gmail dot com
                   ` (2 preceding siblings ...)
  2013-05-15 18:24 ` pinskia at gcc dot gnu.org
@ 2013-05-15 18:44 ` umbricola at gmail dot com
  2013-05-15 18:53 ` pinskia at gcc dot gnu.org
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: umbricola at gmail dot com @ 2013-05-15 18:44 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #4 from Chris Mihelich <umbricola at gmail dot com> ---
Yes indeed, x is loaded from the stack into edi, and y is loaded from the stack
into esi, as the register variable declarations specified.  That's two
registers.  Where are the other two?


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Bug inline-asm/57299] Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures
  2013-05-15 18:08 [Bug inline-asm/57299] New: Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures umbricola at gmail dot com
                   ` (3 preceding siblings ...)
  2013-05-15 18:44 ` umbricola at gmail dot com
@ 2013-05-15 18:53 ` pinskia at gcc dot gnu.org
  2013-05-15 19:20 ` umbricola at gmail dot com
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: pinskia at gcc dot gnu.org @ 2013-05-15 18:53 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #5 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
(In reply to Chris Mihelich from comment #4)
> Yes indeed, x is loaded from the stack into edi, and y is loaded from the
> stack into esi, as the register variable declarations specified.  That's two
> registers.  Where are the other two?

Simple, "m"(*x) cannot use either edi or esi.  Likewise for "m"(*y).  You can
change the *y to *q and *x to *p, it will work.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Bug inline-asm/57299] Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures
  2013-05-15 18:08 [Bug inline-asm/57299] New: Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures umbricola at gmail dot com
                   ` (4 preceding siblings ...)
  2013-05-15 18:53 ` pinskia at gcc dot gnu.org
@ 2013-05-15 19:20 ` umbricola at gmail dot com
  2013-05-15 20:16 ` pinskia at gcc dot gnu.org
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: umbricola at gmail dot com @ 2013-05-15 19:20 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #6 from Chris Mihelich <umbricola at gmail dot com> ---
Ah, but "=m" and "m" operands shouldn't need any register at all: their purpose
is just to declare that a specific piece of memory is written or read in the
assembly code, a declaration that helps the optimizer avoid mistakes.  The GCC
manual sketches this pattern thus:

Note that in the following example the memory input is necessary, otherwise GCC
might optimize the store to x away:

     int foo ()
     {
       int x = 42;
       int *y = &x;
       int result;
       asm ("magic stuff accessing an 'int' pointed to by '%1'"
            : "=&d" (r) : "a" (y), "m" (*y));
       return result;
     }

Clearly this code is not trying to put the pointer y into a second register
that it doesn't use.  The point is to prevent the initialization of x with 42
from being deleted as (apparently) useless.  There is no indication in the
manual that this "m" (*y) would occupy a register, nor is there any good reason
for a register to be consumed in this case.

I agree with your interpretation in this one sense: GCC appears to be assigning
registers to the "m" and "=m" values as you suggest.  That makes my test case
need six registers (not four) instead of the two it really needs.  That is the
defect I was trying to describe.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Bug inline-asm/57299] Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures
  2013-05-15 18:08 [Bug inline-asm/57299] New: Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures umbricola at gmail dot com
                   ` (5 preceding siblings ...)
  2013-05-15 19:20 ` umbricola at gmail dot com
@ 2013-05-15 20:16 ` pinskia at gcc dot gnu.org
  2013-05-15 21:57 ` umbricola at gmail dot com
  2013-05-15 21:59 ` pinskia at gcc dot gnu.org
  8 siblings, 0 replies; 10+ messages in thread
From: pinskia at gcc dot gnu.org @ 2013-05-15 20:16 UTC (permalink / raw)
  To: gcc-bugs

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

Andrew Pinski <pinskia at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |RESOLVED
         Resolution|---                         |INVALID

--- Comment #7 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
(In reply to Chris Mihelich from comment #6)
> I agree with your interpretation in this one sense: GCC appears to be
> assigning registers to the "m" and "=m" values as you suggest.  That makes
> my test case need six registers (not four) instead of the two it really
> needs.  That is the defect I was trying to describe.

Actually it only needs 4 (and not 6) due to holding of the pointer of y and x
can happen with only 2 registers.  And you can use the operands of the m inside
the inline-asm which is why it needs to store the pointer in a register.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Bug inline-asm/57299] Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures
  2013-05-15 18:08 [Bug inline-asm/57299] New: Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures umbricola at gmail dot com
                   ` (6 preceding siblings ...)
  2013-05-15 20:16 ` pinskia at gcc dot gnu.org
@ 2013-05-15 21:57 ` umbricola at gmail dot com
  2013-05-15 21:59 ` pinskia at gcc dot gnu.org
  8 siblings, 0 replies; 10+ messages in thread
From: umbricola at gmail dot com @ 2013-05-15 21:57 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #8 from Chris Mihelich <umbricola at gmail dot com> ---
(In reply to Andrew Pinski from comment #7)
> Actually it only needs 4 (and not 6) due to holding of the pointer of y and
> x can happen with only 2 registers.

That's not what GCC is doing, actually.  When I take out -fPIC and compile, the
disassembly looks like this:

00000000 <f>:
   0:    55                       push   %ebp
   1:    89 e5                    mov    %esp,%ebp
   3:    57                       push   %edi
   4:    56                       push   %esi
   5:    53                       push   %ebx
   6:    8b 7d 08                 mov    0x8(%ebp),%edi
   9:    8b 75 0c                 mov    0xc(%ebp),%esi
   c:    8b 45 08                 mov    0x8(%ebp),%eax
   f:    8b 5d 0c                 mov    0xc(%ebp),%ebx
  12:    8b 55 08                 mov    0x8(%ebp),%edx
  15:    8b 4d 0c                 mov    0xc(%ebp),%ecx
  18:    5b                       pop    %ebx
  19:    5e                       pop    %esi
  1a:    5f                       pop    %edi
  1b:    5d                       pop    %ebp
  1c:    c3                       ret    

You can see that six registers, not four, are being loaded in the body of f.

> And you can use the operands of the m inside the inline-asm which is why it
> needs to store the pointer in a register.

If I gave the "m" operand a name and used the name, or if I referred to, say,
%0 inside the body of the asm statement, you would be correct.  But I didn't. 
There is no reason to give a register to a "m" or "=m" operand that is not
referenced in the asm body, and this is the common case for "m" operands. 
Their main purpose is to prevent incorrect optimizations, not to pass values to
the assembly code.

The spurious register allocation makes "m" operands unusable in most complex
asm statements.  It doesn't take too many memory dependencies to exhaust the
stingy x86 general-purpose register set.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Bug inline-asm/57299] Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures
  2013-05-15 18:08 [Bug inline-asm/57299] New: Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures umbricola at gmail dot com
                   ` (7 preceding siblings ...)
  2013-05-15 21:57 ` umbricola at gmail dot com
@ 2013-05-15 21:59 ` pinskia at gcc dot gnu.org
  8 siblings, 0 replies; 10+ messages in thread
From: pinskia at gcc dot gnu.org @ 2013-05-15 21:59 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #9 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
Oh without optimization 6 registers will be used rather than the 4 that GCC can
do with optimizations turned on.


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2013-05-15 21:59 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-05-15 18:08 [Bug inline-asm/57299] New: Inline assembly memory dependencies produce spurious loads, register pressure, compilation failures umbricola at gmail dot com
2013-05-15 18:14 ` [Bug inline-asm/57299] " pinskia at gcc dot gnu.org
2013-05-15 18:22 ` umbricola at gmail dot com
2013-05-15 18:24 ` pinskia at gcc dot gnu.org
2013-05-15 18:44 ` umbricola at gmail dot com
2013-05-15 18:53 ` pinskia at gcc dot gnu.org
2013-05-15 19:20 ` umbricola at gmail dot com
2013-05-15 20:16 ` pinskia at gcc dot gnu.org
2013-05-15 21:57 ` umbricola at gmail dot com
2013-05-15 21:59 ` pinskia at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).