diff --git a/test/packetmath.cpp b/test/packetmath.cpp index fae4fc7c6..dfde981d6 100644 --- a/test/packetmath.cpp +++ b/test/packetmath.cpp @@ -30,13 +30,16 @@ inline T REF_SUB(const T& a, const T& b) { using UnsignedT = std::make_unsigned_t; return static_cast(static_cast(a) - static_cast(b)); } -template ::IsInteger || !NumTraits::IsSigned, int> = 0> +template ::IsInteger || std::is_same::value, int> = 0> inline T REF_MUL(const T& a, const T& b) { return a * b; } -template ::IsInteger && NumTraits::IsSigned, int> = 0> +template ::IsInteger && !std::is_same::value, int> = 0> inline T REF_MUL(const T& a, const T& b) { - using UnsignedT = std::make_unsigned_t; + // Evaluate in an unsigned type at least as wide as int so that sub-int + // operands are not promoted back to signed int (whose product can overflow); + // the result then wraps modulo 2^bits just like pmul. + using UnsignedT = std::common_type_t, unsigned>; return static_cast(static_cast(a) * static_cast(b)); } @@ -57,8 +60,11 @@ struct madd_impl { }; template -struct madd_impl::IsInteger && NumTraits::IsSigned>> { - using UnsignedScalar = std::make_unsigned_t; +struct madd_impl::IsInteger && !std::is_same::value>> { + // Unsigned type at least as wide as int, so sub-int operands are not promoted + // back to signed int (whose products/sums can overflow); results wrap modulo + // 2^bits like the packet madd/msub ops. + using UnsignedScalar = std::common_type_t, unsigned>; static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Scalar madd(const Scalar& a, const Scalar& b, const Scalar& c) { return static_cast(static_cast(a) * static_cast(b) + @@ -721,25 +727,20 @@ void packetmath() { } } -// C4804: unsafe use of type 'bool' in operation. Unavoidable when Scalar=bool. -#if EIGEN_COMP_MSVC -#pragma warning(push) -#pragma warning(disable : 4804) -#endif + // REF_ADD folds with defined wraparound for signed integers (matching predux, + // which wraps mod 2^N) and with || for bool, avoiding both signed-overflow UB + // and the MSVC C4804 "unsafe use of bool" warning that raw operator+ triggers. ref[0] = Scalar(0); - for (int i = 0; i < PacketSize; ++i) ref[0] += data1[i]; + for (int i = 0; i < PacketSize; ++i) ref[0] = REF_ADD(ref[0], data1[i]); VERIFY(test::isApproxAbs(ref[0], internal::predux(internal::pload(data1)), refvalue) && "internal::predux"); if (!std::is_same::half>::value) { int HalfPacketSize = PacketSize > 4 ? PacketSize / 2 : PacketSize; for (int i = 0; i < HalfPacketSize; ++i) ref[i] = Scalar(0); - for (int i = 0; i < PacketSize; ++i) ref[i % HalfPacketSize] += data1[i]; + for (int i = 0; i < PacketSize; ++i) ref[i % HalfPacketSize] = REF_ADD(ref[i % HalfPacketSize], data1[i]); internal::pstore(data2, internal::predux_half(internal::pload(data1))); VERIFY(test::areApprox(ref, data2, HalfPacketSize) && "internal::predux_half"); } -#if EIGEN_COMP_MSVC -#pragma warning(pop) -#endif // Avoid overflows. if (NumTraits::IsInteger && NumTraits::IsSigned &&