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 };
}
даст лучшую производительность, учитывая текущее состояние компиляторов C/С++, ориентированных на x86-64? Есть ли какие-либо подводные камни по одной или другой версии? Компиляторы (GCC, Clang) всегда могут оптимизировать std::pair
для возврата в rax
и rdx
?
ОБНОВЛЕНИЕ: Как правило, возвращение пары происходит быстрее, если компилятор оптимизирует методы std::pair
(примеры двоичного вывода с GCC 5.3.0 и Clang 3.8.0). Если f()
не встроен, компилятор должен сгенерировать код для записи значения в память, например:
movq b, (%rdi)
movq a, %rax
retq
Но в случае g()
для компилятора достаточно:
movq a, %rax
movq b, %rdx
retq
Поскольку инструкции для записи значений в память обычно медленнее, чем инструкции для записи значений в регистры, вторая версия должна быть быстрее.