C/C++屬於靜態編譯語言,C/C++編譯是將原始碼經由編譯器、彙編器處理產生機器指令,再通過連結器和庫函數結合產生可執行程式。但x86平台和ARM平台屬於不同的架構,指令集也不同,其開發的程式從x86平台遷移到ARM平台時,必須重新編譯。本文介紹從x86平台遷移到倚天雲端服務器時,如何對C/C++中系統宏或函數進行相應修改。
宏相關
從平台相容性來看,系統中的宏可以分為x86平台宏、ARM平台宏以及x86和ARM都支援的平台宏。不同平台的宏格式如下:
ARM平台宏 | x86平台宏 | ARM和x86都支援的宏 |
__arm__ | __amd64__ | __STDC_HOSTED__ |
__thumb__ | i386 | __INT64_TYPE__ |
__ARM_ARCH_4T__ | __k8__ | _LP64 |
__aarch64__ | __SSE2__ | __WCHAR_MAX__ |
built-in函數
built-in函數是GCC編譯器中的內建函數,可以實現一些簡單快捷的功能方便程式的編寫。這些函數大多數都是以__builtin_作為首碼使用。x86平台編譯環境下的built-in函數(類似builtin_ia32_xxx)在倚天雲端服務器中直接編譯會出現編譯失敗。
從x86平台遷移built-in函數到倚天雲端服務器時,需要進行相應修改,如x86平台crc相關builtin_ia32_crc32qi(a, b)需要修改成ARM平台的builtin_aarch64_crc32cb(a, b)。
intrinsic函數
intrinsic函數是與x86 CPU架構密切相關的函數,是SIMD(Single Instruction Multiple Data,單指令多資料)操作的介面。從x86平台遷移到倚天雲端服務器時,主要工作集中在simd相關intrinsic的遷移。
從x86平台遷移intrinsic函數到倚天雲端服務器時,主要有以下兩個步驟:
添加標頭檔(arm_neon.h、arm_sve.h)以支援intrinsics函數在ARM系統上使用。
替換intrinsic,更多資訊,請參見Arm Developer。
以上兩部分的處理指示和資料類型都需要修改成ARM平台支援。例如:
x86的m128 mm_load_ps需要修改為float32x4 vld1q_f32。
由於x86支援AVX指令,寄存器長度為256 bit,而aarch64隻支援128 bit長度的寄存器,因此,需要進行相同語義的展開。例如:m256d mm_add_ps則需要在aarch64上使用兩條SIMD指令vaddq_f32 + vaddq_f32。
倚天雲端服務器支援SVE指令,但由於其編程模式的特殊性,不推薦轉換成SVE intrinsic。您可以參考業界開源的sse2neon專案來解決此問題。
內聯彙編
x86平台的彙編指令與ARM有所不同,從x86平台遷移彙編指令到倚天雲端服務器時,需要將x86平台的彙編指令修改成相同語義的aarch64指令。例如:asm("bswap %0": "=r"(val): "0"(val)) 可以修改成相同語義的sev指令asm("rev %[dst], %[src]": [dst]"=r"(val): [src]"r"(val))。更多資訊,請參見How to Use Inline Assembly Language in C Code。
樣本說明
從x86平台遷移C/C++代碼到倚天雲端服務器時,具體代碼修改樣本如下所示。
原代碼:
#if defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
/* GCC-compatible compiler, targeting x86/x86-64 */
#include <x86intrin.h>
#endif
uint32_t crc32_4k(uint32_t acc, char* buf) {
for (char* end = buf + 4096; buf < end; buf += 4) {
acc = __builtin_ia32_crc32si(acc, *(uint32_t*)buf);
}
return acc;
}修改後代碼:
#if defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
/* GCC-compatible compiler, targeting x86/x86-64 */
#include <x86intrin.h>
#elif defined(__GNUC__) && defined(__ARM_NEON)
/* GCC-compatible compiler, targeting ARM with NEON */
#include <arm_neon.h>
#if defined(__ARM_FEATURE_SVE)
#include <arm_sve.h>
#endif
#endif
uint32_t crc32_4k(uint32_t acc, char* buf) {
for (char* end = buf + 4096; buf < end; buf += 4) {
acc = __builtin_aarch64_crc32cw(acc, *(uint32_t*)buf);
}
return acc;
}