asm,asm volatile和clobbering memory之间的区别

在实现无锁数据结构和时间代码时,往往需要抑制编译器的优化。 通常情况下,人们在clobber列表中使用asm volatilememory来做这件事,但是有时你会看到只是asm volatile或只是一个简单的asm clobbering memory。

这些不同的语句对代码生成有什么影响(特别是在GCC中,因为它不太可能是便携式的)?

仅供参考,这些是有趣的变化:

 asm (""); // presumably this has no effect on code generation asm volatile (""); asm ("" ::: "memory"); asm volatile ("" ::: "memory"); 

请参阅GCC文档中的“Extended Asm”页面 。

通过在asm之后写入volatile关键字,可以防止删除asm指令。 volatile关键字表示该指令具有重要的副作用。 如果可以访问,GCC不会删除一个volatile asm。

没有任何输出操作数的asm指令将被视为易失性asm指令。

你的例子都没有指定输出操作数,所以asmasm volatile表单的行为是相同的:它们在代码中创build一个不能被删除的点(除非被certificate是不可访问的)。

这与无所事事并不完全相同。 看到这个问题的一个虚拟asm ,改变代码生成的例子 – 在这个例子中,循环1000次的代码被vector化成代码,它一次计算循环的16次迭代; 但是在循环内存在一个asm抑制优化( asm必须达到1000次)。

"memory" clobber使GCC认为任何内存都可以由asm块任意读取或写入,这样可以防止编译器重新sorting加载或存储:

这将导致GCC不将内存值保存在汇编指令中的寄存器中,也不会优化存储或加载到该内存。

(虽然这并不妨碍CPU对另一个CPU的加载和存储进行重新sorting,但是您需要真正的内存屏障指令。)

asm ("")什么都不做(或者至less,它不应该做任何事情。

asm volatile ("")也什么都不做。

asm ("" ::: "memory")是一个简单的编译器篱笆。

asm volatile ("" ::: "memory") AFAIK和前面一样。 volatile关键字告诉编译器不允许移动这个汇编块。 例如,如果编译器确定input值在每个调用中都是相同的,则可以将其从循环中提出。 我不太确定在什么条件下,编译器会认为它对组件有足够的了解来优化它的位置,但是volatile关键字完全抑制了这一点。 也就是说,如果编译器试图移动一个没有声明的input或输出的asm语句,我会感到非常惊讶。

顺便说一句, volatile还会阻止编译器在决定输出值未被使用时删除该expression式。 这只会发生,如果有输出值虽然,所以它不适用于asm ("" ::: "memory")

为了完整起见,Kevin Ballard的回答是,Visual Studio 2010提供_ReadBarrier(),_WriteBarrier()和_ReadWriteBarrier()来做同样的事情(VS2010不允许为64位应用程序内联汇编)。

这些不会生成任何指令,但会影响编译器的行为。 这里有一个很好的例子

MemoryBarrier()生成lock or DWORD PTR [rsp], 0