Added dxbcdxil_debug.cpp source file with DXBC/DXIL debugger helpers

Shared between DXBC and DXIL shader debuggers

float dxbc_min(float a, float b);
double dxbc_min(double a, double b);
float dxbc_max(float a, float b);
double dxbc_max(double a, double b);
float round_ne(float x);
float flush_denorm(const float f);
This commit is contained in:
Jake Turner
2024-07-03 07:20:59 +01:00
parent 0406d3766f
commit 71da2b55bb
5 changed files with 201 additions and 105 deletions
+1 -105
View File
@@ -33,35 +33,10 @@
#include "dxbc_container.h"
using namespace DXBCBytecode;
using namespace DXBCDXILDebug;
namespace DXBCDebug
{
static float round_ne(float x)
{
if(!RDCISFINITE(x))
return x;
float rem = remainderf(x, 1.0f);
return x - rem;
}
static float flush_denorm(const float f)
{
uint32_t x;
memcpy(&x, &f, sizeof(f));
// if any bit is set in the exponent, it's not denormal
if(x & 0x7F800000)
return f;
// keep only the sign bit
x &= 0x80000000;
float ret;
memcpy(&ret, &x, sizeof(ret));
return ret;
}
VarType OperationType(const DXBCBytecode::OpcodeType &op)
{
switch(op)
@@ -778,54 +753,6 @@ ShaderVariable TypedUAVLoad(GlobalState::ViewFmt &fmt, const byte *d)
return result;
}
// "NaN has special handling. If one source operand is NaN, then the other source operand is
// returned and the choice is made per-component. If both are NaN, any NaN representation is
// returned."
float dxbc_min(float a, float b)
{
if(RDCISNAN(a))
return b;
if(RDCISNAN(b))
return a;
return a < b ? a : b;
}
double dxbc_min(double a, double b)
{
if(RDCISNAN(a))
return b;
if(RDCISNAN(b))
return a;
return a < b ? a : b;
}
float dxbc_max(float a, float b)
{
if(RDCISNAN(a))
return b;
if(RDCISNAN(b))
return a;
return a >= b ? a : b;
}
double dxbc_max(double a, double b)
{
if(RDCISNAN(a))
return b;
if(RDCISNAN(b))
return a;
return a >= b ? a : b;
}
ShaderVariable sat(const ShaderVariable &v, const VarType type)
{
ShaderVariable r = v;
@@ -5821,37 +5748,6 @@ TEST_CASE("DXBC debugging helpers", "[program]")
CHECK(v2.value.f32v[2] == posinf);
CHECK(v2.value.f32v[3] == posinf);
};
SECTION("test denorm flushing")
{
float foo = 3.141f;
// check normal values
CHECK(flush_denorm(0.0f) == 0.0f);
CHECK(flush_denorm(foo) == foo);
CHECK(flush_denorm(-foo) == -foo);
// check NaN/inf values
CHECK(RDCISNAN(flush_denorm(nan)));
CHECK(flush_denorm(neginf) == neginf);
CHECK(flush_denorm(posinf) == posinf);
// check zero sign bit - bit more complex
uint32_t negzero = 0x80000000U;
float negzerof;
memcpy(&negzerof, &negzero, sizeof(negzero));
float flushed = flush_denorm(negzerof);
CHECK(memcmp(&flushed, &negzerof, sizeof(negzerof)) == 0);
// check that denormal values are flushed, preserving sign
foo = 1.12104e-44f;
CHECK(flush_denorm(foo) != foo);
CHECK(flush_denorm(-foo) != -foo);
CHECK(flush_denorm(foo) == 0.0f);
flushed = flush_denorm(-foo);
CHECK(memcmp(&flushed, &negzerof, sizeof(negzerof)) == 0);
};
};
#endif // ENABLED(ENABLE_UNIT_TESTS)
@@ -0,0 +1,191 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2024 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include "dxbcdxil_debug.h"
namespace DXBCDXILDebug
{
// "NaN has special handling. If one source operand is NaN, then the other source operand is
// returned. If both are NaN, any NaN representation is returned."
float dxbc_min(float a, float b)
{
if(RDCISNAN(a))
return b;
if(RDCISNAN(b))
return a;
return a < b ? a : b;
}
double dxbc_min(double a, double b)
{
if(RDCISNAN(a))
return b;
if(RDCISNAN(b))
return a;
return a < b ? a : b;
}
float dxbc_max(float a, float b)
{
if(RDCISNAN(a))
return b;
if(RDCISNAN(b))
return a;
return a >= b ? a : b;
}
double dxbc_max(double a, double b)
{
if(RDCISNAN(a))
return b;
if(RDCISNAN(b))
return a;
return a >= b ? a : b;
}
float round_ne(float x)
{
if(!RDCISFINITE(x))
return x;
float rem = remainderf(x, 1.0f);
return x - rem;
}
float flush_denorm(const float f)
{
uint32_t x;
memcpy(&x, &f, sizeof(f));
// if any bit is set in the exponent, it's not denormal
if(x & 0x7F800000)
return f;
// keep only the sign bit
x &= 0x80000000;
float ret;
memcpy(&ret, &x, sizeof(ret));
return ret;
}
}; // namespace DXBCDXILDebug
#if ENABLED(ENABLE_UNIT_TESTS)
#include <limits>
#include "catch/catch.hpp"
using namespace DXBCDXILDebug;
TEST_CASE("DXBCDXIL debugging helpers", "[program]")
{
const float posinf = std::numeric_limits<float>::infinity();
const float neginf = -std::numeric_limits<float>::infinity();
const float nan = std::numeric_limits<float>::quiet_NaN();
const float a = 1.0f;
const float b = 2.0f;
SECTION("dxbc_min")
{
CHECK(dxbc_min(neginf, neginf) == neginf);
CHECK(dxbc_min(neginf, a) == neginf);
CHECK(dxbc_min(neginf, posinf) == neginf);
CHECK(dxbc_min(neginf, nan) == neginf);
CHECK(dxbc_min(a, neginf) == neginf);
CHECK(dxbc_min(a, b) == a);
CHECK(dxbc_min(a, posinf) == a);
CHECK(dxbc_min(a, nan) == a);
CHECK(dxbc_min(posinf, neginf) == neginf);
CHECK(dxbc_min(posinf, a) == a);
CHECK(dxbc_min(posinf, posinf) == posinf);
CHECK(dxbc_min(posinf, nan) == posinf);
CHECK(dxbc_min(nan, neginf) == neginf);
CHECK(dxbc_min(nan, a) == a);
CHECK(dxbc_min(nan, posinf) == posinf);
CHECK(RDCISNAN(dxbc_min(nan, nan)));
};
SECTION("dxbc_max")
{
CHECK(dxbc_max(neginf, neginf) == neginf);
CHECK(dxbc_max(neginf, a) == a);
CHECK(dxbc_max(neginf, posinf) == posinf);
CHECK(dxbc_max(neginf, nan) == neginf);
CHECK(dxbc_max(a, neginf) == a);
CHECK(dxbc_max(a, b) == b);
CHECK(dxbc_max(a, posinf) == posinf);
CHECK(dxbc_max(a, nan) == a);
CHECK(dxbc_max(posinf, neginf) == posinf);
CHECK(dxbc_max(posinf, a) == posinf);
CHECK(dxbc_max(posinf, posinf) == posinf);
CHECK(dxbc_max(posinf, nan) == posinf);
CHECK(dxbc_max(nan, neginf) == neginf);
CHECK(dxbc_max(nan, a) == a);
CHECK(dxbc_max(nan, posinf) == posinf);
CHECK(RDCISNAN(dxbc_max(nan, nan)));
};
SECTION("test denorm flushing")
{
float foo = 3.141f;
// check normal values
CHECK(flush_denorm(0.0f) == 0.0f);
CHECK(flush_denorm(foo) == foo);
CHECK(flush_denorm(-foo) == -foo);
// check NaN/inf values
CHECK(RDCISNAN(flush_denorm(nan)));
CHECK(flush_denorm(neginf) == neginf);
CHECK(flush_denorm(posinf) == posinf);
// check zero sign bit - bit more complex
uint32_t negzero = 0x80000000U;
float negzerof;
memcpy(&negzerof, &negzero, sizeof(negzero));
float flushed = flush_denorm(negzerof);
CHECK(memcmp(&flushed, &negzerof, sizeof(negzerof)) == 0);
// check that denormal values are flushed, preserving sign
foo = 1.12104e-44f;
CHECK(flush_denorm(foo) != foo);
CHECK(flush_denorm(-foo) != -foo);
CHECK(flush_denorm(foo) == 0.0f);
flushed = flush_denorm(-foo);
CHECK(memcmp(&flushed, &negzerof, sizeof(negzerof)) == 0);
};
};
#endif // ENABLED(ENABLE_UNIT_TESTS)
@@ -81,4 +81,11 @@ struct SampleGatherSamplerData
BindingSlot binding;
};
float dxbc_min(float a, float b);
double dxbc_min(double a, double b);
float dxbc_max(float a, float b);
double dxbc_max(double a, double b);
float round_ne(float x);
float flush_denorm(const float f);
};
@@ -101,6 +101,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="dxbcdxil_debug.cpp" />
<ClCompile Include="dxbc_bytecode.cpp" />
<ClCompile Include="dxbc_bytecode_editor.cpp" />
<ClCompile Include="dxbc_bytecode_vendorext.cpp" />
@@ -15,6 +15,7 @@
<ClCompile Include="dxbc_stringise.cpp" />
<ClCompile Include="dxbc_bytecode_vendorext.cpp" />
<ClCompile Include="dxbc_bytecode_editor.cpp" />
<ClCompile Include="dxbcdxil_debug.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="dxbc_debug.h" />