C/C++语言迁移

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函数到倚天云服务器时,主要有以下两个步骤:

  1. 添加头文件(arm_neon.h、arm_sve.h)以支持intrinsics函数在ARM系统上使用。

  2. 替换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;
}