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