Set default floating-point environment at compiler boundaries (#1703)

Restore floating-point environment at compiler boundaries, and add a test for this.
This commit is contained in:
Tristan Labelle 2018-11-13 11:51:25 -08:00 коммит произвёл GitHub
Родитель 9bcb3a5b81
Коммит 7a18290e77
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 60 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,7 @@
// RUN: %dxc -E main -T ps_6_0 %s
float3 main() : SV_Target
{
// Some calls known to cause floating point exceptions when evaluated
return float3(pow(0.0f, 0.0f), pow(-1.0f, 0.5f), pow(0.0f, -1.0f));
}

Просмотреть файл

@ -46,6 +46,7 @@
#endif
#include "dxillib.h"
#include <algorithm>
#include <cfloat>
// SPIRV change starts
#ifdef ENABLE_SPIRV_CODEGEN
@ -100,6 +101,28 @@ static void CreateOperationResultFromOutputs(
ppResult);
}
struct DefaultFPEnvScope
{
// _controlfp_s is non-standard and <cfenv>.feholdexceptions doesn't work on windows...?
#ifdef _WIN32
unsigned int previousValue;
DefaultFPEnvScope() {
// No exceptions, preserve denormals & round to nearest.
errno_t error = _controlfp_s(&previousValue, _MCW_EM | _DN_SAVE | _RC_NEAR, _MCW_EM | _MCW_DN | _MCW_RC);
IFT(error == 0 ? S_OK : E_FAIL);
}
~DefaultFPEnvScope() {
unsigned int newValue;
errno_t error = _controlfp_s(&newValue, previousValue, _MCW_EM | _MCW_DN | _MCW_RC);
// During cleanup we can't throw as we might already be handling another one.
DXASSERT(error == 0, "Failed to restore floating-point environment.");
(void)error;
}
#else
DefaultFPEnvScope() {} // Dummy ctor to avoid unused local warning
#endif
};
class HLSLExtensionsCodegenHelperImpl : public HLSLExtensionsCodegenHelper {
private:
CompilerInstance &m_CI;
@ -311,6 +334,8 @@ public:
DxcThreadMalloc TM(m_pMalloc);
try {
DefaultFPEnvScope fpEnvScope;
IFT(CreateMemoryStream(m_pMalloc, &pOutputStream));
// Parse command-line options into DxcOpts
@ -649,6 +674,8 @@ public:
IFC(hlsl::DxcGetBlobAsUtf8(pSource, &utf8Source));
try {
DefaultFPEnvScope fpEnvScope;
CComPtr<AbstractMemoryStream> pOutputStream;
dxcutil::DxcArgsFileSystem *msfPtr = dxcutil::CreateDxcArgsFileSystem(utf8Source, pSourceName, pIncludeHandler);
std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
@ -756,6 +783,8 @@ public:
DxcEtw_DXCompilerDisassemble_Start();
DxcThreadMalloc TM(m_pMalloc);
try {
DefaultFPEnvScope fpEnvScope;
::llvm::sys::fs::MSFileSystem *msfPtr;
IFT(CreateMSFileSystemForDisk(&msfPtr));
std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);

Просмотреть файл

@ -20,6 +20,7 @@
#include <cassert>
#include <sstream>
#include <algorithm>
#include <cfloat>
#include "dxc/DxilContainer/DxilContainer.h"
#include "dxc/Support/WinIncludes.h"
#include "dxc/dxcapi.h"
@ -374,6 +375,7 @@ public:
TEST_METHOD(CodeGenExternRes)
TEST_METHOD(CodeGenExpandTrig)
TEST_METHOD(CodeGenFloatCast)
TEST_METHOD(CodeGenFloatingPointEnvironment)
TEST_METHOD(CodeGenFloatToBool)
TEST_METHOD(CodeGenFirstbitHi)
TEST_METHOD(CodeGenFirstbitLo)
@ -3452,6 +3454,28 @@ TEST_F(CompilerTest, CodeGenFloatCast) {
CodeGenTestCheck(L"..\\CodeGenHLSL\\float_cast.hlsl");
}
struct FPEnableExceptionsScope
{
// _controlfp_s is non-standard and <cfenv> doesn't have a function to enable exceptions
#ifdef _WIN32
unsigned int previousValue;
FPEnableExceptionsScope() {
VERIFY_IS_TRUE(_controlfp_s(&previousValue, 0, _MCW_EM) == 0); // _MCW_EM == 0 means enable all exceptions
}
~FPEnableExceptionsScope() {
unsigned int newValue;
errno_t error = _controlfp_s(&newValue, previousValue, _MCW_EM);
DXASSERT(error == 0, "Failed to restore floating-point environment.");
(void)error;
}
#endif
};
TEST_F(CompilerTest, CodeGenFloatingPointEnvironment) {
FPEnableExceptionsScope fpEnableExceptions;
CodeGenTestCheck(L"..\\CodeGenHLSL\\fpexcept.hlsl");
}
TEST_F(CompilerTest, CodeGenFloatToBool) {
CodeGenTestCheck(L"..\\CodeGenHLSL\\float_to_bool.hlsl");
}