gpt4 book ai didi

c++ - Clang 为直觉上应该等效的表达式提供非常不同的性能

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:53:35 25 4
gpt4 key购买 nike

有人可以向我解释这些表达式之间的这些显着性能差异,我希望它们能提供相似的性能。我在 Release模式下使用 Apple LLVM 版本 5.1 (clang-503.0.38)(基于 LLVM 3.4svn)进行编译。

这是我的测试代码(只需将 CASE 更改为 1、2、3 或 4 来测试自己):

#include <iostream>
#include <chrono>

#define CASE 1

inline int foo(int n) {
return
#if CASE == 1
(n % 2) ? 9 : 6

#elif CASE == 2
(n % 2) == true ? 9 : 6

#elif CASE == 3
6 + (n % 2) * 3

#elif CASE == 4
6 + bool(n % 2) * 3

#endif
;
}

int main(int argc, const char* argv[])
{
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now();

int n = argc;
for (int i = 0; i < 100000000; ++i) {
n += foo(n);
}

end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;

std::cout << "elapsed time: " << elapsed_seconds.count() << "\n";
std::cout << "value: " << n << "\n";

return 0;
}

这是我得到的时间:

CASE   EXPRESSION                TIME
1 (n % 2) ? 9 : 6 0.1585
2 (n % 2) == true ? 9 : 6 0.3491
3 6 + (n % 2) * 3 0.2559
4 6 + bool(n % 2) * 3 0.1906

下面是 CASE 1 和 CASE 2 在汇编上的区别:

案例 1:

Ltmp12:
LBB0_1: ## =>This Inner Loop Header: Depth=1
##DEBUG_VALUE: main:argv <- RSI
##DEBUG_VALUE: i <- 0
.loc 1 24 0 ## /Test/main.cpp:24:0
movl %ebx, %ecx
andl $1, %ecx
leal (%rcx,%rcx,2), %ecx
Ltmp13:
.loc 1 48 14 ## /Test/main.cpp:48:14
leal 6(%rbx,%rcx), %ebx

案例 2:

Ltmp12:
LBB0_1: ## =>This Inner Loop Header: Depth=1
##DEBUG_VALUE: main:argv <- RSI
##DEBUG_VALUE: i <- 0
.loc 1 24 0 ## /Test/main.cpp:24:0
movl %ebx, %ecx
shrl $31, %ecx
addl %ebx, %ecx
andl $-2, %ecx
movl %ebx, %edx
subl %ecx, %edx
cmpl $1, %edx
sete %cl
movzbl %cl, %ecx
leal (%rcx,%rcx,2), %ecx
Ltmp13:
.loc 1 48 14 ## /Test/main.cpp:48:14
leal 6(%rbx,%rcx), %ebx

下面是 CASE 3 和 CASE 4 在汇编上的区别:

案例 3:

Ltmp12:
LBB0_1: ## =>This Inner Loop Header: Depth=1
##DEBUG_VALUE: main:argv <- RSI
##DEBUG_VALUE: i <- 0
.loc 1 24 0 ## /Test/main.cpp:24:0
movl %ebx, %ecx
shrl $31, %ecx
addl %ebx, %ecx
andl $-2, %ecx
movl %ebx, %edx
subl %ecx, %edx
leal (%rdx,%rdx,2), %ecx
Ltmp13:
.loc 1 48 14 ## /Test/main.cpp:48:14
leal 6(%rbx,%rcx), %ebx

案例 4:

Ltmp12:
LBB0_1: ## =>This Inner Loop Header: Depth=1
##DEBUG_VALUE: main:argv <- RSI
##DEBUG_VALUE: i <- 0
.loc 1 24 0 ## /Test/main.cpp:24:0
movl %ebx, %ecx
andl $1, %ecx
negl %ecx
andl $3, %ecx
Ltmp13:
.loc 1 48 14 ## /Test/main.cpp:48:14
leal 6(%rbx,%rcx), %ebx

最佳答案

这个答案目前只涵盖了前两种情况的区别。


(n % 2) 的可能值是多少?当然,它是 01,对吧?

错了。它是 01 -1。因为 n 是一个有符号整数,并且 the result of % can be negative .

(n % 2) ? 6 : 9 将表达式 n % 2 隐式转换为 bool。此转换的结果是 true IFF 值非零。因此,转换等同于 (n % 2) != 0

(n % 2) == true 中? 6 : 9,对于比较 (n % 2) == true通常的算术转换应用于两侧(注意 bool 是算术类型)。 true 被提升为值 1int。所以转换等同于 (n % 2) == 1

这两个转换 (n % 2) != 0(n % 2) == 1 对于负值 n 产生不同的结果:令n = -1。那么n % 2 == -1,并且-1 != 0true,但是-1 == 1false

因此,编译器必须引入一些额外的复杂性来处理符号。

如果您将 n 设为无符号整数,或以任何其他方式消除符号问题(例如通过比较 n % 2 !=假)。


我是通过查看程序集输出得到这个想法的,尤其是下面一行:

shrl    $31, %eax

一开始使用最高位对我来说毫无意义,直到我意识到最高位被用作符号。

关于c++ - Clang 为直觉上应该等效的表达式提供非常不同的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22819232/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com