Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The gcc manual is still unsatisfying in this regard. What can asm volatile statements be reordered with? If all the compiler knows is that running the asm is important, what does it assume about where the asm must run? The manual suggests it's not entirely conservative.

In a 2007 mailing list post Re: [PATCH 6/8] i386: bitops: Don't mark memory as clobbered unnecessarily, Linus says:

[I]t's a good idea to have the "memory" clobber there too, because the semantics of the "volatile" just aren't very well defined from a code movement standpoint.

Panel
titleWarning: Misinformation on Sandeep.S's GCC-Inline-Assembly-HOWTO

This otherwise useful howto (GCC-Inline-Assembly-HOWTO) claims the following:

If our assembly statement must execute where we put it, (i.e. must not be moved out of a loop as an optimization), put the keyword volatile after asm and before the ()'s. So to keep it from moving, deleting and all...

However, this contradicts the gcc manual, which clearly states that the volatile keyword on asm statements will not stop the compiler from moving the asm instructions, including across jump instructions (see Extended Asm in the GCC manual).

...

If your assembler instructions access memory in an unpredictable fashion, add `memory' to the list of clobbered registers. This will cause GCC to not keep memory values cached in registers across the assembler instruction and not optimize stores or loads to that memory. You will also want to add the volatile keyword if the memory affected is not listed in the inputs or outputs of the asm, as the `memory' clobber does not count as a side-effect of the asm.

In a 1996 mailing list post Re: Is clobber "memory" in include/asm-i386/system.h necessary?, Linus said:

...

LKML post, Trent Piepho found that in the assembly output for the following code, x[20] = 1 is ellided:

No Format

extern int a; /* keep asm from being elided for having no used output */
static inline void bar(void) { asm("call bar" : "=m"(a) : : "memory"); }
/* float x can't alias asm's output int a */
void foo(float *x) { x[20] = 1; bar(); x[20] = 2; }

I was able to confirm this behavior using the KNOPPIX 3.6 bootable CD image, which has gcc 3.3.4.

He concludes that:

Adding a memory clobber tells gcc that the asm modifies memory. It doesn't modify un-aliased local variables in registers. It does modify aliased local variables. It does not read from memory. gcc will move or elide a memory write before an asm with a memory clobber if nothing else (besides the asm) could see the write. A memory clobber doesn't count as a side-effect either, a non-volatile asm without unused outputs will be elided, even if has a memory clobber.

Linus responds:

It does leave us with very few ways of saying that an asm can read memory, and so it might be good to have it clarified that "volatile" implies that (at least with the memory clobber).

Volatile keyword elsewhere

...

* doc/extend.texi (Extended Asm): Rewrite asm volatile description.

In a 1996 mailing list post Re: Is clobber "memory" in include/asm-i386/system.h necessary?, Linus said:

Essentially, think of the "memory" thing as a serializing flag rather than as a "this instruction changes memory" flag. It is extremely important that gcc not re-order memory instructions across these serializing instructions, because otherwise you might find that gcc moves a memory load over the serializing instruction and then you lose...

He changes his mind a bit in 2007, now believing that "memory" means that the asm instructions write to memory but do not read it.