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;
}