При попытке оптимизировать возвращаемые значения на x86_64 я заметил странную вещь. А именно, учитывая код:
#include <cstdint>
#include <tuple>
#include <utility>
using namespace std;
constexpr uint64_t a = 1u;
constexpr uint64_t b = 2u;
pair<uint64_t, uint64_t> f() { return {a, b}; }
tuple<uint64_t, uint64_t> g() { return tuple<uint64_t, uint64_t>{a, b}; }
Clang 3.8 выводит этот код сборки для f
:
movl $1, %eax
movl $2, %edx
retq
а для g
:
movl $2, %eax
movl $1, %edx
retq
которые выглядят оптимальными. Однако, когда скомпилирован с GCC 6.1, в то время как сгенерированная сборка для f
идентична выпуску Clang, сборка, сгенерированная для g
является:
movq %rdi, %rax
movq $2, (%rdi)
movq $1, 8(%rdi)
ret
Похоже, что тип возвращаемого значения классифицируется как MEMORY по GCC, но как INTEGER by Clang. Я могу подтвердить, что связывание кода Clang с кодом GCC, такой код может привести к ошибкам сегментации (Clang-вызов GCC-скомпилирован g()
, который записывает туда, где имеет место %rdi
) и возвращаемое недопустимое значение (вызов GCC Clang-compiled g()
). Какой компилятор неисправен?
Связанный:
- g++ и clang++ несовместимость со стандартной библиотекой при создании разделяемых библиотек?
- [cxx-abi-dev] Нетривиальный конструктор перемещения