簡體   English   中英

為什么 `asm volatile(""::: "memory")` 可以用作編譯器屏障?

[英]Why can `asm volatile("" ::: "memory")` serve as a compiler barrier?

眾所周知, asm volatile (""::: "memory")可以用作編譯器屏障,以防止編譯器重新排序匯編指令。 例如,在https://preshing.com/20120625/memory-ordering-at-compile-time/的“顯式編譯器障礙”一節中提到了它。

但是,我能找到的所有文章都只提到asm volatile (""::: "memory")可以用作編譯器屏障,而沒有給出"memory" clobber 可以有效地形成編譯器屏障的原因。 GCC 在線文檔只說所有特殊的破壞者"memory"所做的就是告訴編譯器匯編代碼可能會執行 memory 讀取或寫入操作數列表中指定的操作以外的操作。 但是這樣的語義是如何導致編譯器停止對 memory 指令重新排序的嘗試呢? 我試圖回答自己但失敗了,所以我在這里問:為什么asm volatile (""::: "memory")可以作為編譯器屏障,基於"memory" clobber 的語義? 請注意,我問的是“編譯器屏障”(在編譯時有效),而不是更強的“內存屏障”(在運行時有效)。 為方便起見,我在下面的 GCC 在線文檔中摘錄了"memory"破壞者的語義:

"memory" clobber 告訴編譯器,匯編代碼執行 memory 讀取或寫入輸入和 output 操作數中列出的項目以外的項目(例如,訪問由輸入參數之一指向的 ZCD69B4957F06CD000D818D7BF3D619)。 為確保 memory 包含正確的值,GCC 可能需要在執行asm之前將特定寄存器值刷新到 memory。 此外,編譯器不假定在asm之前從 memory 讀取的任何值在asm之后保持不變; 它會根據需要重新加載它們。 有效地使用"memory"破壞器 forms 為編譯器提供讀/寫 memory 屏障。

如果一個變量可能被讀取或寫入,那么它發生的順序很重要。 "memory"破壞器的目的是確保asm語句中的讀取和/或寫入發生在程序執行的正確位置。

asm語句之后發生在源中的 C 變量值的任何讀取必須在目標計算機的編譯器生成的程序集 output 中的內存破壞asm語句之后,否則它可能正在讀取 asm 語句之前的值改變了它。

asm語句之前對源中的 C var 的任何讀取同樣必須保持之前的順序,否則它可能會錯誤地讀取修改后的值。

類似的推理適用於在任何帶有"memory" clobber 的asm語句之前/之后對 C 變量的賦值(寫入)。 就像 function 調用“不透明” function 一樣,編譯器無法看到的定義。

任何讀取或寫入都不能與屏障在任一方向上重新排序,因此屏障之前的任何操作都不能與屏障之后的任何操作重新排序,反之亦然。


另一種看待它的方式:實際機器 memory 的內容必須與 C 抽象機相匹配。 編譯器生成的 asm 必須尊重這一點,通過在asm("":::"memory")語句開始之前將任何變量值從寄存器存儲到 memory 語句,然后它必須假設任何具有副本的寄存器變量值可能不再是最新的。 因此,如果需要,必須重新加載它們。

對於"memory" clobber,這種讀取所有內容/寫入所有內容的假設是使asm語句在編譯時完全不會重新排序的原因。 所有訪問,甚至volatile訪問。 volatile已經是一個沒有"=..." output 操作數的asm()語句隱含,並且是阻止它被完全優化的原因(以及 memory clobber)。


請注意,只有可能“可達”的 C 變量會受到影響。 例如,只要 asm 語句本身沒有地址作為輸入,轉義分析仍然可以讓編譯器將本地int i保存在跨越"memory" clobber 的寄存器中。

就像 function 調用一樣: for (int i=0;i<10;i++) {foobar("%d\n", i);}可以將循環計數器保存在寄存器中,然后將其復制到第二個參數- 每次迭代都為 foobar 傳遞寄存器。 foobar 不可能有對i的引用,因為它的地址沒有存儲在任何地方或傳遞到任何地方。

(這對於 memory 屏障用例來說很好;也沒有其他線程可以擁有它的地址。)


有關的:

我要補充一點: memory只是一個編譯器指令。 推測處理器可以重新排序指令。 為了防止這種情況發生,需要明確的 memory 屏障調用。 請參閱 memory 屏障上的 Linux 文檔。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM