Difference between asm, asm volatile and clobbering memory

When embedding loose data structures and synchronization code, it is often necessary to suppress compiler optimization. Usually people do this using asm volatile with memory in the clobber list, but sometimes you only see asm volatile or just asm simple key memory.

What effect do these different statements have on code generation (especially in GCC, since it is unlikely to be portable)?

For reference, these are interesting options:

 asm (""); // presumably this has no effect on code generation asm volatile (""); asm ("" ::: "memory"); asm volatile ("" ::: "memory"); 
+57
c gcc inline-assembly
Jan 21 '13 at 23:35
source share
3 answers

See the "Extended Asm" page in the GCC documentation .

You can prevent the removal of the asm statement by writing the volatile keyword after asm . [...] The volatile keyword indicates that the instruction has important side effects. GCC will not remove volatile asm if it is reachable.

as well as

An asm instruction without any output operands will be processed identically to the asm volatile instruction.

None of your examples have output operands defined, therefore asm volatile forms asm and asm volatile behave the same way: they create a point in the code that cannot be deleted (unless it is proved that it is not available).

This is not quite the same as doing nothing. Look at this question for an example of a fictitious asm that changes the generation of the code - in this example, the code that runs the loop 1000 times is vectorized into code that calculates 16 iterations of the loop at the same time; but the presence of asm inside the loop prevents optimization ( asm should be reached 1000 times).

The "memory" overflow causes GCC to assume that any memory can be arbitrarily read or written by the asm block, so the compiler will not reorder the load or save through it:

This will cause GCC to not store the memory values ​​cached in registers in the assembler instruction and will not optimize storage or load into that memory.

(This does not prevent the processor from reordering workloads and storages relative to another processor, though; for this you need real instructions for protecting memory.)

+53
Jan 22 '13 at 1:10
source share

asm ("") does nothing (or at least it should not do anything.

asm volatile ("") also does nothing.

asm ("" ::: "memory") is a simple compiler fence.

asm volatile ("" ::: "memory") AFAIK is similar to the previous one. The volatile keyword tells the compiler that it is not allowed to move this assembly block. For example, it may be loop-aligned if the compiler decides that the input values ​​are the same for each call. I'm not sure under what conditions the compiler will decide that it understands the assembly enough to try to optimize its placement, but the volatile keyword completely blocks this. However, I would be very surprised if the compiler tried to move the asm statement that did not have the declared inputs or outputs.

By the way, volatile also prevents the compiler from deleting an expression if it decides that the output values ​​are not used. This can only happen if there are output values, so it does not apply to asm ("" ::: "memory") .

+7
Jan 21 '13 at 23:41
source share

Just for completeness , Lily Ballard's answer , Visual Studio 2010 offers _ReadBarrier() , _WriteBarrier() and _ReadWriteBarrier() to do the same (VS2010 does not allow built-in assembly for 64-bit applications).

They do not generate any instructions, but affect the behavior of the compiler. Good example here .

MemoryBarrier() generates a lock or DWORD PTR [rsp], 0

+1
Jan 22 '13 at 0:55
source share



All Articles