多连续无符号整数比较的安全优化及类型双关实现正确性探讨
关于std::tuple比较的汇编优化与类型双关正确性的问题
当在GCC 13.2和Clang 18.0.1编译器开启-O3优化时,由四个std::uint16_t构成的std::tuple的operator<生成的汇编代码优化效果不佳。而采用reinterpret_cast和联合(union)两种*类型双关(type punning)*实现的比较逻辑,则能生成优化后的汇编代码。
编辑说明:因问题遭差评,特此补充:默认实现的汇编包含3个条件分支,在高性能循环中影响显著,而另外两种实现无分支。
技术问询
- 这两种类型双关实现是否正确?
- 若不正确,需满足哪些条件才能保证其正确性?
- 假设存在可编译期验证的正确性测试,为何编译器不直接生成优化后的汇编代码?
测试代码
#include <cstdint> #include <tuple> #include <bit> using TupleU16 = std::tuple<std::uint16_t, std::uint16_t, std::uint16_t, std::uint16_t>; bool less(TupleU16 lhs, TupleU16 rhs) { return lhs < rhs; } constexpr bool canSafelyUseTypePunning() { TupleU16 t; std::uint16_t* val0 = &std::get<0>(t); std::uint16_t* val1 = &std::get<1>(t); std::uint16_t* val2 = &std::get<2>(t); std::uint16_t* val3 = &std::get<3>(t); if constexpr (std::endian::native == std::endian::little) { return sizeof(TupleU16) == 8 && (val0 - val3) == 3 && (val0 - val2) == 2 && (val0 - val1) == 1; } else if constexpr (std::endian::native == std::endian::big) { return sizeof(TupleU16) == 8 && (val3 - val0) == 3 && (val2 - val0) == 2 && (val1 - val0) == 1; } else { return false; } } bool less2(TupleU16 lhs, TupleU16 rhs) { // cannot be constexpr static_assert(canSafelyUseTypePunning()); auto* lhsp = reinterpret_cast<const std::uint64_t*>(&lhs); auto* rhsp = reinterpret_cast<const std::uint64_t*>(&rhs); return *lhsp < *rhsp; } bool less3(TupleU16 lhs, TupleU16 rhs) { // can be constexpr static_assert(canSafelyUseTypePunning()); union U { std::uint64_t u64; TupleU16 tu16; }; return U{.tu16 = lhs}.u64 < U{.tu16 = rhs}.u64; }
内容的提问来源于stack exchange,提问作者MarkB
相关产品推荐
相关产品推荐

