核心模式 NEON¶
TL;DR 總結¶
僅使用 NEON 指令,或不依賴於支援程式碼的 VFP 指令
將您的 NEON 程式碼隔離在一個單獨的編譯單元中,並使用 '-march=armv7-a -mfpu=neon -mfloat-abi=softfp' 進行編譯
在呼叫您的 NEON 程式碼前後分別呼叫 kernel_neon_begin() 和 kernel_neon_end()
不要在您的 NEON 程式碼中睡眠,並注意它將在停用搶佔的情況下執行
簡介¶
可以在核心模式下執行的程式碼中使用 NEON 指令(在某些情況下,也可以使用 VFP 指令)。但是,出於效能原因,NEON/VFP 暫存器檔案不會像常規暫存器檔案那樣在每次上下文切換或異常發生時都儲存和恢復,因此需要一些手動干預。此外,對於可能睡眠 [即,可能呼叫 schedule()] 的程式碼需要特別注意,因為由於下面概述的原因,NEON 或 VFP 指令將在不可搶佔的部分中執行。
延遲儲存和恢復¶
NEON/VFP 暫存器檔案使用延遲儲存(在 UP 系統上)和延遲恢復(在 SMP 和 UP 系統上)進行管理。這意味著暫存器檔案保持“活動”狀態,並且僅在多個任務爭用 NEON/VFP 單元時(或者,在 SMP 的情況下,當任務遷移到另一個核心時)才會儲存和恢復。延遲恢復的實現方式是在每次上下文切換後停用 NEON/VFP 單元,導致隨後發出 NEON/VFP 指令時發生陷阱,從而允許核心介入並在必要時執行恢復。
核心模式下對 NEON/VFP 單元的任何使用都不應干擾這一點,因此需要“急切”地儲存 NEON/VFP 暫存器檔案,並顯式啟用 NEON/VFP 單元,以便在首次後續使用時不會生成異常。這由函式 kernel_neon_begin() 處理,應在發出任何核心模式 NEON 或 VFP 指令之前呼叫。同樣,使用後應再次停用 NEON/VFP 單元,以確保使用者模式在下次使用時會命中延遲恢復陷阱。這由函式 kernel_neon_end() 處理。
核心模式下的中斷¶
出於效能和簡單性的考慮,決定不為核心模式 NEON/VFP 暫存器內容提供儲存/恢復機制。這意味著只有在保證不觸及 NEON/VFP 暫存器的情況下,才能允許中斷核心模式 NEON 部分。因此,核心中適用以下規則和限制: * 不允許在中斷上下文中使用 NEON/VFP 程式碼; * 不允許 NEON/VFP 程式碼睡眠; * NEON/VFP 程式碼在停用搶佔的情況下執行。
如果延遲是一個問題,可以在您的程式碼中 NEON 暫存器都不活動的地方背靠背呼叫 kernel_neon_end() 和 kernel_neon_begin()。(如果在 meantime 中沒有發生上下文切換,則對 kernel_neon_begin() 的其他呼叫應該相當便宜)
VFP 和支援程式碼¶
早期版本的 VFP(版本 3 之前)依賴於軟體支援來實現 IEEE-754 相容的下溢處理等。當 VFP 單元需要此類軟體輔助時,它會透過引發未定義指令異常來向核心發出訊號。核心透過檢查 VFP 控制暫存器和當前指令和引數來響應,並在軟體中模擬該指令。
目前尚未為在核心模式下執行的 VFP 指令實現此類軟體輔助。如果遇到這種情況,核心將失敗並生成 OOPS。
將 NEON 程式碼與普通程式碼分離¶
編譯器不知道 kernel_neon_begin() 和 kernel_neon_end() 的特殊含義,即只允許在呼叫這些相應函式之間發出 NEON/VFP 指令。此外,如果選擇了 -mfpu=neon,GCC 可能會在 -O3 級別生成它自己的 NEON 指令,即使核心當前是在 -O2 級別編譯的,如果不採取特殊措施,未來的更改可能會導致 NEON/VFP 指令出現在意想不到的位置。
因此,在核心中使用 NEON/VFP 的推薦和唯一支援的方法是遵守以下規則
將 NEON 程式碼隔離在一個單獨的編譯單元中,並使用 '-march=armv7-a -mfpu=neon -mfloat-abi=softfp' 進行編譯;
從 *未* 使用 GCC 標誌 '-mfpu=neon' 設定構建的編譯單元中,發出對 kernel_neon_begin()、kernel_neon_end() 以及包含 NEON 程式碼的單元的呼叫。
由於核心是使用 '-msoft-float' 編譯的,因此以上將保證 NEON 和 VFP 指令都只會在任何最佳化級別下出現在指定的編譯單元中。
NEON 彙編器¶
只要遵循上述規則,就支援 NEON 彙編器,沒有其他注意事項。
GCC 生成的 NEON 程式碼¶
GCC 選項 -ftree-vectorize(由 -O3 隱含)嘗試利用隱式並行性,並從普通 C 原始碼生成 NEON 程式碼。只要遵循上述規則,就完全支援這一點。
NEON 行內函數¶
也支援 NEON 行內函數。但是,由於使用 NEON 行內函數的程式碼依賴於 GCC 標頭 <arm_neon.h>(其中 #includes <stdint.h>),除了上述規則之外,還應注意以下事項
使用 '-ffreestanding' 編譯包含 NEON 行內函數的單元,以便 GCC 使用其內建版本的 <stdint.h>(這是一個核心不提供的 C99 標頭);
最後包含 <arm_neon.h>,或者至少在 <linux/types.h> 之後包含