This is the mail archive of the
gcc-help@gcc.gnu.org
mailing list for the GCC project.
Re: Inlined assembly instruction pushed out of loop in GCC 4.4.1/ARM
- From: Andrew Haley <aph at redhat dot com>
- To: Simon Kagstrom <simon dot kagstrom at netinsight dot net>
- Cc: gcc-help at gcc dot gnu dot org
- Date: Tue, 18 Aug 2009 15:35:22 +0100
- Subject: Re: Inlined assembly instruction pushed out of loop in GCC 4.4.1/ARM
- References: <20090818155811.5fd256fd@marrow.netinsight.se>
Simon Kagstrom wrote:
> Hi!
>
> I'm having a compile issue with the Linux kernel for ARM and GCC 4.4.1
> (also occurs in 4.3.3 at least). The code (from orion_nand.c in the
> Linux kernel, cooked down) looks like this:
>
> void *vobb = (void*)0x12345678;
>
> void orion_nand_read_buf(uint8_t *buf, int len)
> {
> void *io_base = vobb;
> uint64_t *buf64;
> int i = 0;
>
> buf64 = (uint64_t *)buf;
> while (i < len/8) {
> uint64_t x;
> asm ("ldrd\t%0, [%1]" : "=r" (x) : "r" (io_base));
This is wrong. It tells gcc that an address is input to the asm and
a uint64_t is returned. But it doesn't tell gcc that some memory
at io_base is being used. So, it's legitimate to hoist the asm out
of the loop.
Add a memory clobber and an earlyclobber:
asm ("ldrd\t%0, [%1]" : "=&r" (x) : "r" (io_base));
> GCC is built with crosstool-ng and is called like this:
>
> arm-unknown-linux-gnueabi-gcc -mcpu=arm926ej-s -c tst.c -o /tmp/tst.o -Os
>
> the problem does not occur without optimization, but with any -O level.
> It can be solved by making the inline asm statement volatile, but the
> Linux developers are not happy with that change:
>
> http://lists.infradead.org/pipermail/linux-mtd/2009-July/026399.html
>
>
> Now, I'm not sure that the inline assembly is completely correct
> either. The ldrd instruction
>
> http://infocenter.arm.com/help/topic/com.arm.doc.ddi0290g/Chddeedh.html
>
> requires that the destination register should be even (I presume since
> it puts the result in a register pair), and maybe that should be
> encoded in the output operand constraints? At least GCC 3.4.4 gives me
>
> Error: destination register must be even -- `ldrd r1,[r2]'
>
> when compiling this code.
I think that is a bug.
> So is this a GCC bug or should I head back to the Linux people with it?
No-one here is going to fix bugs in gcc 3.4.4. I think you'll need to
use an explicit register variable to work round it.
Andrew.