[英]The difference between asm, asm volatile and clobbering memory
在實現無鎖數據結構和時序代碼時,通常需要抑制編譯器的優化。 通常人們在clobber列表中使用asm volatile
with memory
來做這件事,但是你有時會看到asm volatile
或者僅僅是一個簡單的asm
clobbering內存。
這些不同的陳述對代碼生成有什么影響(特別是在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
指令將被視為與volatileasm
指令完全相同。
您的示例都沒有指定輸出操作數,因此asm
和asm volatile
表單的行為相同:它們在代碼中創建一個可能不會被刪除的點(除非它被證明是無法訪問的)。
這與什么都不做完全不一樣。 請參閱此問題 ,以獲取更改代碼生成的虛擬asm
示例 - 在該示例中,循環1000次循環的代碼被矢量化為代碼,該代碼一次計算循環的16次迭代; 但是在循環內存在asm
抑制優化( asm
必須達到1000次)。
"memory"
崩潰使得GCC假設任何內存都可以由asm
塊任意讀取或寫入,因此會阻止編譯器在其上重新排序加載或存儲:
這將導致GCC不保持跨匯編指令緩存在寄存器中的內存值,而不是優化存儲器或加載到該內存。
(但這並不妨礙CPU相對於另一個CPU重新排序加載和存儲;您需要真正的內存屏障指令。)
asm ("")
什么都不做(或者至少,它不應該做任何事情。
asm volatile ("")
也什么也沒做。
asm ("" ::: "memory")
是一個簡單的編譯器圍欄。
asm volatile ("" ::: "memory")
AFAIK與之前相同。 volatile
關鍵字告訴編譯器不允許移動此程序集塊。 例如,如果編譯器確定每次調用中的輸入值相同,則可以將其從循環中提升。 我不確定在什么條件下編譯器會決定它對程序集的了解程度足以嘗試優化其位置,但volatile
關鍵字完全抑制了這一點。 也就是說,如果編譯器試圖移動沒有聲明輸入或輸出的asm
語句,我會非常驚訝。
順便說一句, volatile
也會阻止編譯器在確定輸出值未使用時刪除它。 這只有在有輸出值時才會發生,所以它不適用於asm ("" ::: "memory")
。
僅僅為了完整了Lily Ballard的回答 ,Visual Studio 2010提供了_ReadBarrier()
, _WriteBarrier()
和_ReadWriteBarrier()
來做同樣的事情(VS2010不允許64位應用程序的內聯匯編)。
這些不會生成任何指令,但會影響編譯器的行為。 一個很好的例子是在這里 。
MemoryBarrier()
生成lock or DWORD PTR [rsp], 0
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.