将 8 个 uint8_t 组合成一个 uintmax_t 的最快方法是什么?
What is the fastest way to combine 8 uint8_t into a single uintmax_t?
我希望优化一段使用 popcnt
来计算 uint8_t
之间差异的代码。我认为将 8 个 uint8_t
组合成一个 uintmax_t
并改为使用 popcnt64
会更快,这样 popcnt 操作不必被调用 8 倍以上。将 8 uint8_t
送入 popcnt64
的最快方法是什么?我可以使用某种铸件吗?我应该使用位操作吗?我不知道 C++ 的内部工作原理,所以我不确定进行此转换的最快方法是什么。
假设您不关心字节序——您只想将 uint8_t
视为 uint64_t
而您不关心 uint8_t
的顺序– 然后你可以只使用 std::memcpy
来做双关语:
std::uint64_t combine(std::array<std::uint8_t, 8> b) {
static_assert(sizeof(b) == sizeof(std::uint64_t));
static_assert(std::is_trivially_copyable_v<std::uint64_t>);
static_assert(std::is_trivially_copyable_v<decltype(b)>);
std::uint64_t result;
std::memcpy(&result, b.data(), sizeof(result));
return result;
}
generated assembly只是returns参数:
combine(std::array<unsigned char, 8ul>): # @combine(std::array<unsigned char, 8ul>)
mov rax, rdi
ret
使用任何其他类型双关使得你不得不担心严格的别名规则或类型对齐。只需使用 std::memcpy
并让编译器处理它就足够简单了
请注意,从 C++ 调用 popcnt
的任何变体的最简单方法是使用 std::bitset::count
。因此,不用 __builtin_popcountll(my_u64)
或 __popcnt64(my_u64)
,您只需编写 std::bitset<64>{my_u64}.count()
即可立即获得可移植代码。
我希望优化一段使用 popcnt
来计算 uint8_t
之间差异的代码。我认为将 8 个 uint8_t
组合成一个 uintmax_t
并改为使用 popcnt64
会更快,这样 popcnt 操作不必被调用 8 倍以上。将 8 uint8_t
送入 popcnt64
的最快方法是什么?我可以使用某种铸件吗?我应该使用位操作吗?我不知道 C++ 的内部工作原理,所以我不确定进行此转换的最快方法是什么。
假设您不关心字节序——您只想将 uint8_t
视为 uint64_t
而您不关心 uint8_t
的顺序– 然后你可以只使用 std::memcpy
来做双关语:
std::uint64_t combine(std::array<std::uint8_t, 8> b) {
static_assert(sizeof(b) == sizeof(std::uint64_t));
static_assert(std::is_trivially_copyable_v<std::uint64_t>);
static_assert(std::is_trivially_copyable_v<decltype(b)>);
std::uint64_t result;
std::memcpy(&result, b.data(), sizeof(result));
return result;
}
generated assembly只是returns参数:
combine(std::array<unsigned char, 8ul>): # @combine(std::array<unsigned char, 8ul>)
mov rax, rdi
ret
使用任何其他类型双关使得你不得不担心严格的别名规则或类型对齐。只需使用 std::memcpy
并让编译器处理它就足够简单了
请注意,从 C++ 调用 popcnt
的任何变体的最简单方法是使用 std::bitset::count
。因此,不用 __builtin_popcountll(my_u64)
或 __popcnt64(my_u64)
,您只需编写 std::bitset<64>{my_u64}.count()
即可立即获得可移植代码。