NDK編譯——x86 支援
NDK 引入對 x86
ABI 的支援,其允許原生程式碼在 CPU 可支援 IA-32 指令集的 Android 裝置上執行。
概覽
如需生成 x86 機器程式碼,請將 x86
新增到 Application.mk
檔案中的 APP_ABI
定義。
例如:
APP_ABI := armeabi armeabi-v7a x86如需瞭解有關定義
APP_ABI
變數的詳細資訊,請參閱 Application.mk
。
構建系統將生成的庫放入 $PROJECT/libs/x86/
(其中 $PROJECT
表示您的專案的根目錄)並其嵌入 /lib/mips/
下的 APK 中。
在相容的基於 x86 的裝置上安裝 APK 時,Android 軟體包提取這些庫,將它們置於應用的私有資料目錄下。
在 Google Play 商店中,伺服器過濾應用,以便消費者只能看到可在其裝置所配備的 CPU 上執行的原生庫。
x86 對 ARM NEON 行內函數的支援
通過與標準 ARM NEON 行內函數標頭 arm_neon.h
具有相同名稱的 C/C++ 語言標頭為 ARM NEON 行內函數提供支援。 這些標頭適用於所有 NDK x86 工具鏈。 它們將 NEON 行內函數轉換為原生 x86 SSE 行內函數。
此解決方案的特性包括下列各項:
- 預設使用 SSE 到 SSSE3 指令集將 ARM NEON 移植到 Intel SSE,涵蓋所有 NEON 函式的 93% 左右(1869 個(總數為 2009 個))。
- 將 ARM NEON 128 位向量重新定義為均等的 x86 SIMD 資料。
- 如果存在 1:1 對應關係,則將來自 ARM NEON 的一些函式重新定義為 Intel SSE。
- 使用 Intel SIMD(如果它將生成一個性能結果)實現某些 ARM NEON 函式。
- 使用序列化解決方案實現部分剩餘的 NEON 函式,併發送相應的“低效能”編譯器警告。
效能
大多數情況下,您應該能夠取得類似於從 ARM NEON 程式碼獲取的效能。 實現最佳結果的建議包括:
- 使用 16 位資料對齊以實現更快地載入和儲存速度。
- 避免將 NEON 函式與常量一起使用。使用常量會導致因必須載入常量而造成的效能損失。 如果您必須使用常量,則嘗試在熱點環路之外初始化它們。 如果可以,將它們替換為邏輯運算和比較運算。
- 儘量避免使用標記為“依次實現”的函式,因為它們需要將來自暫存器的資料儲存到記憶體。 替代的做法是依次處理它們並重新載入。您可以更改用於向量化整個埠的資料型別或演算法,而不是進行序列化。
與 ARM 版本的已知差異
大多數情況下,對於 NEON,x86 實現生成與 ARM 實現相同的結果。x86 實現幾乎始終傳遞 NEON 測試。 但在幾個極端情況下,x86 實現生成不同於其 ARM 實現的結果。 已知的不相容性如下:
VRECPS/VRECPSQ
如果一個運算元為 +/- 無限值,則第二個運算元為 +/- 0.0:- x86 CPU 返回
QNaN Indefinite
。如需瞭解有關 QNaN 浮點不定數的詳細資訊,請參閱 Intel® 64 和 IA-32 架構軟體開發者手冊中的“4.2.2 浮點資料型別”與“4.8.3.7 QNaN 浮點不定數”。
- x86 CPU 返回
VRSQRTS/VRSQRTSQ
如果一個運算元為 +/- 無限值,則第二個運算元為 +/- 0.0:- x86 CPU 返回
QNaN Indefinite
。如需瞭解有關 QNaN 浮點不定數的詳細資訊,請參閱 Intel® 64 和 IA-32 架構軟體開發者手冊中的“4.2.2 浮點資料型別”與“4.8.3.7 QNaN 浮點不定數”。
- x86 CPU 返回
VMAX/VMAXQ
如果一個運算元為 NaN,或兩個運算元均為 +/- 0.0:- 在 ARM CPU 上,浮點最大值工作原理如下:
- max(+0.0, -0.0) = +0.0。
- 如果任意輸入為 NaN,則對應的結果元素為預設 NaN。
- 在 x86 CPU 上,浮點最大值工作原理如下:
- 如果其中一個源運算元為 NaN,則返回第二個源運算元。
- 如果兩個源運算元均等於 0,則返回第二個源運算元。
- 在 ARM CPU 上,浮點最大值工作原理如下:
VMIN/VMINQ
如果一個運算元為 NaN,或兩個運算元均為 +/- 0.0:- 在 ARM CPU 上,浮點最小值工作原理如下:
- min(+0.0, -0.0) = -0.0。
- 如果任意輸入為 NaN,則對應的結果元素為預設 NaN。
- 在 x86 CPU 上,浮點最小值工作原理如下:
- 如果其中一個源運算元為 NaN,則返回第二個源運算元。
- 如果兩個源運算元均等於 0,則返回第二個源運算元。
- 在 ARM CPU 上,浮點最小值工作原理如下:
VRECPE/VRECPEQ
這些指令在 ARM 和 x86 CPU 上提供不同程度的準確性。如需瞭解有關這些差異的詳細資訊,請參閱 ARM 網站上的如何使用 VRECPE/VRECPEQ 進行反向預估?以及 Intel® 64 和 IA-32 架構軟體開發者手冊第 2 冊第 4-281 頁。VRSQRTE/VRSQRTEQ
- 如果某個運算元為負數或負無限大,則
- 在 ARM CPU 上,這些指令預設返回一個(正的)NaN。如需瞭解有關此結果的詳細資訊,請參閱 ARM 編譯器工具鏈彙編程式參考。
- 在 x86 CPU 上,這些指令返回一個(負的)QNaN 不定數。如需瞭解有關此結果的詳細資訊,請參閱 Intel® 64 和 IA-32 架構軟體開發者手冊第 1 冊附錄 E 部分 E.4.2.3。
- 如果某個運算元為負數或負無限大,則
示例程式碼
如果您的專案確保新增 arm_neon.h
標頭,則在您的 APP_ABI
的定義中定義 include x86
。 然後,構建系統將您的程式碼移植到 x86。
有關將 ARM NEON 移植到 x86 SSE 的原理的示例,請參閱 hello-neon 示例。
獨立工具鏈
您可以將 x86
ABI 納入您自己的工具鏈中。如需瞭解詳細資訊,請參閱獨立工具鏈。
相容性
x86 支援至少需要 Android 2.3 版本(Android API 級別 9)。如果您的專案檔案面向較早的 API 級別,但新增 x86 作為目標平臺,則 NDK 構建指令碼自動為您選擇正確的原生平臺標頭/庫的集合。