Implement separate DAZ/FTZ control for Windows

Flush-To-Zero (FTZ) controls whether subnormal results of floating-point
operations are replaced by zero. Denormals-Are-Zero (DAZ) controls
whether subnormal operands of floating-point operations are treated as
zero.

The Windows _controlfp() function does not offer a way to set each of
them separately, but defines four constants that represent the four
possible combinations. By first retrieving the current status of the
control word to check whether the other mode is on or off, we can
selectively enable or disable each mode.

Bug: b/169904252
Change-Id: I895220ff7c980e5b0ddc0b8a62649a8c32b99d73
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/63328
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/System/CPUID.cpp b/src/System/CPUID.cpp
index 7e0809b..1496ff7 100644
--- a/src/System/CPUID.cpp
+++ b/src/System/CPUID.cpp
@@ -154,18 +154,38 @@
 	return cores;
 }
 
-void CPUID::setFlushToZero(bool enable)
+void CPUID::setFlushToZero(bool enableFTZ)
 {
 #if defined(_MSC_VER)
-	_controlfp(enable ? _DN_FLUSH : _DN_SAVE, _MCW_DN);
+	unsigned int current = _controlfp(0, 0) & _MCW_DN;
+	if(current == _DN_SAVE || current == _DN_SAVE_OPERANDS_FLUSH_RESULTS)  // DAZ off
+	{
+		_controlfp(enableFTZ ? _DN_SAVE_OPERANDS_FLUSH_RESULTS : _DN_SAVE, _MCW_DN);
+	}
+	else  // DAZ on
+	{
+		_controlfp(enableFTZ ? _DN_FLUSH : _DN_FLUSH_OPERANDS_SAVE_RESULTS, _MCW_DN);
+	}
 #else
 	                     // Unimplemented
 #endif
 }
 
-void CPUID::setDenormalsAreZero(bool enable)
+void CPUID::setDenormalsAreZero(bool enableDAZ)
 {
-	// Unimplemented
+#if defined(_MSC_VER)
+	unsigned int current = _controlfp(0, 0) & _MCW_DN;
+	if(current == _DN_SAVE || current == _DN_FLUSH_OPERANDS_SAVE_RESULTS)  // FTZ off
+	{
+		_controlfp(enableDAZ ? _DN_FLUSH_OPERANDS_SAVE_RESULTS : _DN_SAVE, _MCW_DN);
+	}
+	else  // FTZ on
+	{
+		_controlfp(enableDAZ ? _DN_FLUSH : _DN_SAVE_OPERANDS_FLUSH_RESULTS, _MCW_DN);
+	}
+#else
+	                     // Unimplemented
+#endif
 }
 
 }  // namespace sw