Set*_*son 3 c++ optimization assembly
为什么返回std::pair
或boost::tuple
要少得多效率比参考返回?在我测试的实际代码中,通过非const引用而不是std::pair
在内核中设置数据可以将代码加速20%.
作为一个实验,我查看了三个最简单的情况,包括将两个(预定义的)整数添加到两个整数:
使用内部内联函数通过引用修改整数
使用两个内部内联函数按值返回整数
使用内部内联函数返回复制到结果的std :: pair.
使用g++ -c $x -Wall -Wextra -O2 -S
相同的汇编代码编译结果,以便按引用传递并按值返回整数:
__Z7getPairiRiS_:
LFB19:
pushq %rbp
LCFI0:
leal 1023(%rdi), %eax
addl $31, %edi
movl %eax, (%rsi)
movq %rsp, %rbp
LCFI1:
movl %edi, (%rdx)
leave
ret
Run Code Online (Sandbox Code Playgroud)
(通过参考代码:
#include <utility>
inline void myGetPair(const int inp, int& a, int& b) {
a = 1023 + inp;
b = 31 + inp;
}
void getPair(const int inp, int& a, int& b) {
myGetPair(inp, a, b);
}
Run Code Online (Sandbox Code Playgroud)
使用单独的右值:
#include <utility>
inline int myGetPair1(int inp) {
return 1023 + inp;
}
inline int myGetPair2(int inp) {
return 31 + inp;
}
void getPair(const int inp, int& a, int& b) {
a = myGetPair1(inp);
b = myGetPair2(inp);
}
Run Code Online (Sandbox Code Playgroud)
)
但是,使用std :: pair会添加五个额外的汇编语句:
__Z7getPairiRiS_:
LFB18:
leal 31(%rdi), %eax
addl $1023, %edi
pushq %rbp
LCFI0:
salq $32, %rax
movq %rsp, %rbp
LCFI1:
orq %rdi, %rax
movq %rax, %rcx
movl %eax, (%rsi)
shrq $32, %rcx
movl %ecx, (%rdx)
leave
ret
Run Code Online (Sandbox Code Playgroud)
其代码几乎与前面的示例一样简单:
#include <utility>
inline std::pair<int,int> myGetPair(int inp) {
return std::make_pair(1023 + inp, 31 + inp);
}
void getPair(const int inp, int& a, int& b) {
std::pair<int,int> result = myGetPair(inp);
a = result.first;
b = result.second;
}
Run Code Online (Sandbox Code Playgroud)
任何知道编译器内部工作原理的人都可以帮助解决这个问题吗?该升压元组页提到的性能损失的元组与传递通过引用,但没有链接文件的回答这个问题.
我喜欢的std ::对它们传递按引用语句的原因是,它使函数的意图多少清晰的在许多情况下,尤其是当其他参数的输入,以及将要被修改的.
我尝试使用VC++ 2008,使用cl.exe /c /O2 /FAs foo.cpp
(即"仅编译且不链接","优化速度"和"在注释中使用匹配的源代码行转储汇编输出").这就是getLine()
最终的结果.
"byref"版本:
PUBLIC ?getPair@@YAXHAAH0@Z ; getPair
; Function compile flags: /Ogtpy
; COMDAT ?getPair@@YAXHAAH0@Z
_TEXT SEGMENT
_inp$ = 8 ; size = 4
_a$ = 12 ; size = 4
_b$ = 16 ; size = 4
?getPair@@YAXHAAH0@Z PROC ; getPair, COMDAT
; 9 : myGetPair(inp, a, b);
mov eax, DWORD PTR _inp$[esp-4]
mov edx, DWORD PTR _a$[esp-4]
lea ecx, DWORD PTR [eax+1023]
mov DWORD PTR [edx], ecx
mov ecx, DWORD PTR _b$[esp-4]
add eax, 31 ; 0000001fH
mov DWORD PTR [ecx], eax
; 10 : }
ret 0
?getPair@@YAXHAAH0@Z ENDP ; getPair
Run Code Online (Sandbox Code Playgroud)
" std::pair
byval " - 回归版:
PUBLIC ?getPair@@YAXHAAH0@Z ; getPair
; Function compile flags: /Ogtpy
; COMDAT ?getPair@@YAXHAAH0@Z
_TEXT SEGMENT
_inp$ = 8 ; size = 4
_a$ = 12 ; size = 4
_b$ = 16 ; size = 4
?getPair@@YAXHAAH0@Z PROC ; getPair, COMDAT
; 8 : std::pair<int,int> result = myGetPair(inp);
mov eax, DWORD PTR _inp$[esp-4]
; 9 :
; 10 : a = result.first;
mov edx, DWORD PTR _a$[esp-4]
lea ecx, DWORD PTR [eax+1023]
mov DWORD PTR [edx], ecx
; 11 : b = result.second;
mov ecx, DWORD PTR _b$[esp-4]
add eax, 31 ; 0000001fH
mov DWORD PTR [ecx], eax
; 12 : }
ret 0
?getPair@@YAXHAAH0@Z ENDP ; getPair
Run Code Online (Sandbox Code Playgroud)
如您所见,实际装配是相同的; 唯一的区别在于错误的名称和评论.