我的环境是 ubuntu18,glibc 2.7,下面是我的代码:
#include <stdio.h>
#include <string.h>
int main() {
char str[20] = "aacdf";
int str_num = strlen(str);
printf("str num is %d \n",str_num);
return 0;
}
编译之后,直接 gdb 调试,查看汇编代码,发现 strlen()
的 函数的实现主要使用了 3 个汇编指令完成。
1,pcmpeqb,求掩码,上面是5个字符,求掩码之后就变成 0 0 0 0 -1 -1 -1 这种数据。
2,pmovmskb,转移掩码。
3,bsf,这个是位扫码指令,直接扫掩码,扫到 1 停止。
这些 是 SSE2 的指令集,实际上在 SSE4.1 提供了一个 pcmpistr
指令,可以完成上面 3 个指令干的活。
下面来看一下 glibc 库 2.7 版本的 strlen()
函数的代码实现,文件是 string/strlen.c
如下:
从代码可以看到,使用的是 C语言,里面没有嵌入汇编代码,所以这些 C程序 被编译成 什么样的 汇编指令,取决于编译系统,也就是 gcc,我的 gcc 版本是7.5,但很明显,编译系统是有点滞后的,SSE4.1 的 pcmpistr
指令2007年已经出了,但是直到 2018 年,gcc 7.5 编译 strlen
函数的时候还是没能用上 pcmpistr
指令。相差10多年,这个时间差就给了很多做性能优化的公司很多机会。
再看另一个例子。代码如下:
int main() {
double a = 4.0;
double b = 20.0;
double c = 40.0;
double d = (a * b) + c;
return d;
}
这个例子编译出来的汇编指令,也没用 FMA 指令。
实际上如果编译系统比较厉害,是可以编译出这种代码,如下:
__asm__("movsd -0x20(%rbp),%xmm0");
__asm__("movsd -0x18(%rbp),%xmm1");
__asm__("movsd -0x10(%rbp),%xmm2");
__asm__("vfmadd213sd %xmm2,%xmm1,%xmm0");
相关阅读:
由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。如果读者有任何宝贵意见,可以加我微信 Loken1,QQ:2338195090。