替换x86 pcmpestrm汇编指令
现象描述
编译报错Error: unknown mnemonic 'pcmpestrm' -- 'pcmpestrm'。
问题原因
pcmpestrm指令是x86指令集中SSE4中的指令。根据指令介绍,其用途是根据指定的比较模式,判断字符串str2的字节是否在str1中出现,将每个字节的对比结果返回(最大长度16字节)。该指令是典型的x86复杂指令,通过一条指令即完成复杂的字符串匹配功能,鲲鹏架构中无类似实现。对于这种指令,需要彻底了解其功能,通过C代码重新实现其功能。
指令介绍:
https://software.intel.com/sites/landingpage/IntrinsicsGuide/#techs=SSE4_2&expand=835
https://docs.microsoft.com/zh-cn/previous-versions/visualstudio/visual-studio-2010/bb514080(v=vs.100)
处理步骤
如下代码段是Impala中对pcmpestrm指令的调用,该调用参考Intel的_mm_cmpestrm接口实现将pcmpestrm指令封装成SSE4_cmpestrm:
template<int MODE> static inline __m128i SSE4_cmpestrm(__m128i str1, int len1, __m128i str2, int len2) { #ifdef __clang__ /// Use asm reg rather than Yz output constraint to workaround LLVM bug 13199 - /// clang doesn't support Y-prefixed asm constraints. register volatile __m128i result asm ("xmm0"); __asm__ __volatile__ ("pcmpestrm %5, %2, %1": "=x"(result) : "x"(str1), "xm"(str2), "a"(len1), "d"(len2), "i"(MODE) : "cc"); #else __m128i result; __asm__ __volatile__ ("pcmpestrm %5, %2, %1": "=Yz"(result) : "x"(str1), "xm"(str2), "a"(len1), "d"(len2), "i"(MODE) : "cc"); #endif return result; }
从指令介绍中看,不同的模式所执行的操作差异较大,完全实现指令功能所需代码行太多。结合代码中对接口的调用,实际使用到的模式为PCMPSTR_EQUAL_ANY |PCMPSTR_UBYTE_OPS。即按照字节长度做匹配,对比str2中的每个字符是否在str1中出现,若出现,则将对应bit位置置1。
根据识别到的功能进行代码实现:
#include <arm_neon.h> typedefunion __attribute__((aligned(16))) __oword { int32x4_t m128i; uint8_tm128i_u8[16]; } __oword; template <intMODE> staticinlineuint16_tSSE4_cmpestrm(int32x4_tstr1, intlen1, int32x4_tstr2, intlen2){ __oword a, b; a.m128i = str1; b.m128i = str2; uint16_t result = 0; uint16_t i = 0; uint16_t j = 0; // Impala中用到的模式 STRCHR_MODE = PCMPSTR_EQUAL_ANY | PCMPSTR_UBYTE_OPS for (i = 0; i < len2; i++) { for (j = 0; j < len1; j++) { if (a.m128i_u8[j] == b.m128i_u8[i]) { result |= (1 << i); } } } return result; }

无直接替代指令的场景,需要结合指令功能、所需功能共同分析,切忌生搬硬套直接代码复制替换。
父主题: 嵌入式汇编类问题