MSVC: Fix use of POPCNT instruction without CPU check

The __popcnt family of intrinsics with MSVC generates directly the
POPCNT instruction and are documented to do so:
  https://msdn.microsoft.com/en-us/library/bb385231.aspx

So we can't use __popcnt unless the target processor supports it.

[ChangeLog][Windows] Fixed a bug that caused applications to crash with
"Illegal instruction" faults when compiled with Visual Studio and run on
some older processors.

Task-number: QTBUG-58446
Change-Id: I445bb15619f6401494e8fffd149d83bd2a7e3376
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
This commit is contained in:
Thiago Macieira 2017-01-26 19:38:20 -08:00
parent 099f286870
commit 72f49ef46a

View File

@ -638,6 +638,17 @@ Q_ALWAYS_INLINE uint qt_builtin_clzs(quint16 v) Q_DECL_NOTHROW
{
return qt_builtin_clz(v) - 16U;
}
// Neither MSVC nor the Intel compiler define a macro for the POPCNT processor
// feature, so we're using either the SSE4.2 or the AVX macro as a proxy (Clang
// does define the macro). It's incorrect for two reasons:
// 1. It's a separate bit in CPUID, so a processor could implement SSE4.2 and
// not POPCNT, but that's unlikely to happen.
// 2. There are processors that support POPCNT but not AVX (Intel Nehalem
// architecture), but unlike the other compilers, MSVC has no option
// to generate code for those processors.
// So it's an acceptable compromise.
#if defined(__AVX__) || defined(__SSE4_2__) || defined(__POPCNT__)
#define QALGORITHMS_USE_BUILTIN_POPCOUNT
Q_ALWAYS_INLINE uint qt_builtin_popcount(quint32 v) Q_DECL_NOTHROW
{
@ -658,6 +669,8 @@ Q_ALWAYS_INLINE uint qt_builtin_popcountll(quint64 v) Q_DECL_NOTHROW
return __popcnt64(v);
}
#endif // MSVC 64bit
#endif // __AVX__ || __SSE4_2__ || __POPCNT__
#endif // MSVC
#endif // QT_HAS_CONSTEXPR_BUILTINS