我正在尝试编写一个strcmp版本,该版本利用了利用GCC内部函数的SSE4.2新指令。
这是我到目前为止的代码:
#include <stdio.h>
#include <smmintrin.h>
int main(int argc, char const *argv[])
{
int n;
const char str1[16] = "foo bar";
const char str2[16] = "foo quxx";
/* Safety check for SSE4.2 support */
__builtin_cpu_init();
if(__builtin_cpu_supports("sse4.2"))
puts("Ok SSE4.2");
else
{
puts("Nok SSE4.2");
return -__LINE__;
}
/* Load strings into registers */
__v16qi xmm1 = __builtin_ia32_loaddqu(str1);
__v16qi xmm2 = __builtin_ia32_loaddqu(str2);
/* Print to check registers were loaded correctly */
printf("xmm1: %s\nxmm2: %s\n", (const char *) &xmm1, (const char *) &xmm2);
/* Perform compare */
n = __builtin_ia32_pcmpistri128(xmm1, xmm2, (_SIDD_CMP_EQUAL_EACH | _SIDD_LEAST_SIGNIFICANT));
/* Print result */
printf("n: %d\n", n);
return 0;
}
它应该打印第一个不同字节的索引,但是总是打印0。
我已经尝试调试了几个小时,直到在生成的程序集中看到它为止:
call printf
movdqa -64(%rbp), %xmm1
movdqa -80(%rbp), %xmm0
pcmpistri $8, %xmm1, %xmm0
movl %ecx, %eax
pcmpistrm $8, %xmm1, %xmm0
movl %eax, -84(%rbp)
movl -84(%rbp), %eax
根据Wikibooks,如果有输出索引的指令(就像我要使用的pcmpistri
一样),结果将保存在ECX
寄存器中,但是,如果我正确地记住,则紧跟在[ C0]使用pcmpistri
覆盖该寄存器!
我认为这可能是使我发疯的错误,但我没有组装经验,我可能错了。
有人遇到此问题吗?有人知道如何解决吗?
[我已经在Ubuntu 16.04(实际上是Windows上的bash)下使用EAX
,-O0
和-O1
(显然是-O2
)使用GCC 5.4和6.2。
让我认为这是一个GCC错误,是来自Visual Studio 2017的undex MSVC编译的类似代码正常工作:
-msse4.2
Yo可能会惊讶地发现,实际上反汇编代码以相反的顺序(即从左到右)呈现每个指令的参数列表。因此,“ move%ecx,%eax”实际上是“ MOV eax,ecx”!只需在“指令级别”中以调试模式逐步运行代码并跟踪寄存器更改。