diff --git a/include/denormals.h b/include/denormals.h index f89325ac1..e08669b2b 100644 --- a/include/denormals.h +++ b/include/denormals.h @@ -4,27 +4,37 @@ #ifndef DENORMALS_H #define DENORMALS_H - #ifdef __SSE__ -#include -#endif -#ifdef __SSE3__ -#include +#include +#ifdef __GNUC__ +#include #endif +// Intel® 64 and IA-32 Architectures Software Developer’s Manual, +// Volume 1: Basic Architecture, +// 11.6.3 Checking for the DAZ Flag in the MXCSR Register +int inline can_we_daz() { + alignas(16) unsigned char buffer[512] = {0}; +#if defined(LMMS_HOST_X86) + _fxsave(buffer); +#elif defined(LMMS_HOST_X86_64) + _fxsave64(buffer); +#endif + // Bit 6 of the MXCSR_MASK, i.e. in the lowest byte, + // tells if we can use the DAZ flag. + return ((buffer[28] & (1 << 6)) != 0); +} +#endif // Set denormal protection for this thread. -// To be on the safe side, don't set the DAZ flag for SSE2 builds, -// even if most SSE2 CPUs can handle it. void inline disable_denormals() { -#ifdef __SSE3__ - /* DAZ flag */ - _MM_SET_DENORMALS_ZERO_MODE( _MM_DENORMALS_ZERO_ON ); -#endif - #ifdef __SSE__ - /* FTZ flag */ - _MM_SET_FLUSH_ZERO_MODE( _MM_FLUSH_ZERO_ON ); + /* Setting DAZ might freeze systems not supporting it */ + if (can_we_daz()) { + _MM_SET_DENORMALS_ZERO_MODE( _MM_DENORMALS_ZERO_ON ); + } + /* FTZ flag */ + _MM_SET_FLUSH_ZERO_MODE( _MM_FLUSH_ZERO_ON ); #endif }