所述X86-64 ABI指定两个返回寄存器:rax和rdx,在大小两个64位(8个字节).
假设x86-64是唯一的目标平台,这两个功能中的哪一个:
uint64_t f(uint64_t * const secondReturnValue) {
/* Calculate a and b. */
*secondReturnValue = b;
return a;
}
std::pair<uint64_t, uint64_t> g() {
/* Calculate a and b, same as in f() above. */
return { a, b };
}
Run Code Online (Sandbox Code Playgroud)
考虑到针对x86-64的C/C++编译器的当前状态,会产生更好的性能吗?使用一个版本或其他版本是否存在性能方面的任何陷阱?编译器(GCC,Clang)总是能够优化std::pair返回rax和rdx吗?
更新:通常,如果编译器优化std::pair方法(使用GCC 5.3.0和Clang 3.8.0的二进制输出示例),则返回一对更快.如果f()没有内联,编译器必须生成代码以将值写入内存,例如:
movq b, (%rdi)
movq a, %rax
retq
Run Code Online (Sandbox Code Playgroud)
但是如果g()编译器满足要求:
movq a, %rax …Run Code Online (Sandbox Code Playgroud) 我期望std :: pair和std :: tuple具有类似的行为。但事实证明,与std :: pair相比,std :: tuple生成更差的asm代码。
https://gcc.godbolt.org/z/Ri4M8z-gcc 10.0.0每晚构建,-O3 -std=c++17
针对x86-64 System V ABI进行编译
#include <utility>
std::pair<long, long> test_pair() {
return { 1, 2 };
}
Run Code Online (Sandbox Code Playgroud)
# returned in RDX:RAX
test_pair():
mov eax, 1
mov edx, 2
ret
Run Code Online (Sandbox Code Playgroud)
#include <tuple>
std::tuple<long, long> test_tuple() {
return { 1, 2 };
}
Run Code Online (Sandbox Code Playgroud)
# returned via hidden pointer, not packed into registers
test_tuple():
mov QWORD PTR [rdi], 2
mov QWORD PTR [rdi+8], 1
mov rax, rdi
ret
Run Code Online (Sandbox Code Playgroud)
这两个函数都返回两个值。test_pair使用寄存器存储期望值;但是test_tuple将值存储在堆栈中,这似乎是未优化的。为什么这两个函数的行为不同?