c-为什么寄存器操作数的TEST比内存和立即数操作数的CMP运行得慢



假设我在一个大数据集上迭代,根据用户提供的变量,我会进行区分大小写或不区分大小写的排序。我认为,因为这个用户提供的值永远不会改变,所以最好将其放入寄存器,例如:

int main(int argc, char * argv[])
{
clock_t t0, t1;
int sort = 1;
t0 = clock();
register int case_insensitive_sort = sort;
int z = 0;
for (int i=0; i < 1e8; i++) {
if (case_insensitive_sort) {
z += 3; // for debugging to see where it's going
} else {
z -= 5;
}
};
t1 = clock();
printf("The function took %fs to complete.n", ((double)(t1-t0))/CLOCKS_PER_SEC);
t0 = clock();
int case_insensitive_sort2 = sort;
z = 0;
for (int i=0; i < 1e8; i++) {
if (case_insensitive_sort2) {
z += 3; // for debugging to see where it's going
} else {
z -= 5;
}
};
t1 = clock();
printf("The function took %fs to complete.n", ((double)(t1-t0))/CLOCKS_PER_SEC);
return 0;
}

下面是编译器输出的一个示例——https://godbolt.org/z/7KrGzr.似乎有了register前缀,寄存器中会有一个比较,看看它是否为0:

testl   %ebx, %ebx

如果没有它,它可以与内存地址进行比较:

cmpl    $0, -12(%rbp)

然而,当我在本地运行时,没有register版本要快得多:

函数需要0.255494秒才能完成。

函数耗时0.188364秒完成。

为什么会这样?我认为使用寄存器而不是进行内存比较会更快。


更新:感谢您在这方面提供的所有帮助。从Peter的建议和相关答案来看,最大的改进不是从registercase_insensitive_sort,而是在循环vars:上进行

register int case_insensitive_sort = sort;
register int z = 0;
for (register int i=0; i < 1e8; i++) { ...

从中我得到了以下两者之间的改进:

函数需要0.255494s才能完成寄存器(之前(
该函数用了0.038112s才完成寄存器(之后(
在没有寄存器的情况下,该函数需要0.252963秒才能完成。

  1. 在不启用编译器优化的情况下进行任何微观优化都毫无意义
  2. 对编译器进行优化时忽略register关键字
  3. 你的测试没有测试任何东西

启用编译器优化时,生成的代码完全相同。https://godbolt.org/z/Tfjn9x

最新更新