Versions Compared

Key

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

...

Even if you use "volatile" the compiler will analyze the input operands, output operands and clobber list of each asm() and may reorder two asm() sequences if it determines that they don't depend on one another. The "memory" clobber list item will stop that since it means "updates memory in an unpredictable way". When you throw syncs's and isync's around it's even true. The other way to prevent reordering is to put everything into a single asm().

You should have a memory operand constraint if you change a known location; "known" in the sense that the compiler can deduce the relationship between it and other values visible in the local scope. For example if there is a pointer p and you load or modify *p you'll need "m"(*p) or "=m"(*p), respectively. You need to do this even if you don't use that constraint number (or name) in your assembly code. On a PowerPC some memory reference instructions use two registers to calculate an effective address instead of an offset and a register, so you'll need both a register constraint for the base register and a memory constraint to tell the compiler the effect of the instruction, e.g.:

asm("lwarx %0,0,%1" : "=r"(result) : "r"(p), "m"(*p))

The memory-ref constraint tells the compiler that the value of *p is needed, preventing it from possibly optimizing away a prior store to some location known to be aliased to *p.

If you can't write a simple constraint for an access to memory then you should have "memory" on the clobber list. Yes, even if you don't change memory. This situation would arise if you were to add a run-time offset to a pointer and dereference the result. If the compiler has been keeping memory values cached in registers it will have to flush them all before a read or write to an unpredictable location on the chance that one of the cached locations may be the target. If you do change memory and need to use the memory-clobber constraint then you should use "asm volatile" instead of just "asm"; "volatile" keeps optimization from removing the asm code which is important if the code has some crucial side effect that the compiler can't deduce from the constraints. Remember that the compiler doesn't analyze the actual instructions in inline assembly code.

Example 1. Here we alter the output "msr" early on (in the first instruction, in fact) so we use the ampersand. We also mark it as output-only ("=") instead of in-out ("+") because we don't care what the value is before the asm. The use of "volatile" and "memory" makes sure that the compiler won't move instructions across the inline assembler code during the course of optimization. We need that because the inline code is changing the Machine State Register and hence the context in which instructions are executed; the isync instruction just prevents reordering by the processor not by the compiler. The compiler doesn't look at the instructions inside the asm, just at the lists of inputs, outputs and clobbers. (The "\n\t" at the end of each instruction just makes the assembly code output generated with -S look nice.)

...