Skip to content

Commit abd5649

Browse files
committed
Code review. Fix float comparisons. Pass clamp args in a buffer
1 parent 57289e6 commit abd5649

3 files changed

Lines changed: 109 additions & 53 deletions

File tree

include/dxc/Test/HlslTestUtils.h

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -470,15 +470,19 @@ inline bool GetTestParamUseWARP(bool defaultVal) {
470470

471471
#ifdef FP_SUBNORMAL
472472

473-
inline bool isdenorm(float f) { return FP_SUBNORMAL == std::fpclassify(f); }
473+
template <typename T = float>
474+
inline bool isdenorm(T f) {
475+
return FP_SUBNORMAL == std::fpclassify(f);
476+
}
474477

475478
#else
476479

477-
inline bool isdenorm(float f) {
478-
return (std::numeric_limits<float>::denorm_min() <= f &&
479-
f < std::numeric_limits<float>::min()) ||
480-
(-std::numeric_limits<float>::min() < f &&
481-
f <= -std::numeric_limits<float>::denorm_min());
480+
template <typename T = float>
481+
inline bool isdenorm(T f) {
482+
return (std::numeric_limits<T>::denorm_min() <= f &&
483+
f < std::numeric_limits<T>::min()) ||
484+
(-std::numeric_limits<T>::min() < f &&
485+
f <= -std::numeric_limits<T>::denorm_min());
482486
}
483487

484488
#endif // FP_SUBNORMAL
@@ -526,6 +530,31 @@ inline bool isnanFloat16(uint16_t val) {
526530
uint16_t ConvertFloat32ToFloat16(float val) throw();
527531
float ConvertFloat16ToFloat32(uint16_t val) throw();
528532

533+
inline bool CompareDoubleULP(
534+
const double &fsrc, const double &fref, int64_t ULPTolerance,
535+
hlsl::DXIL::Float32DenormMode mode = hlsl::DXIL::Float32DenormMode::Any) {
536+
if (fsrc == fref) {
537+
return true;
538+
}
539+
if (std::isnan(fsrc)) {
540+
return std::isnan(fref);
541+
}
542+
543+
if (mode == hlsl::DXIL::Float32DenormMode::Any) {
544+
// If denorm expected, output can be sign preserved zero. Otherwise output
545+
// should pass the regular ulp testing.
546+
if (isdenorm(fref) && fsrc == 0 && std::signbit(fsrc) == std::signbit(fref))
547+
return true;
548+
}
549+
550+
// For FTZ or Preserve mode, we should get the expected number within
551+
// ULPTolerance for any operations.
552+
int64_t diff = *((const DWORD64 *)&fsrc) - *((const DWORD64 *)&fref);
553+
554+
int64_t uDiff = diff < 0 ? -diff : diff;
555+
return uDiff <= (unsigned int)ULPTolerance;
556+
}
557+
529558
inline bool CompareFloatULP(
530559
const float &fsrc, const float &fref, int ULPTolerance,
531560
hlsl::DXIL::Float32DenormMode mode = hlsl::DXIL::Float32DenormMode::Any) {

tools/clang/unittests/HLSLExec/ExecutionTest.cpp

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,6 @@ class ExecutionTest {
628628
bool m_D3DInitCompleted = false;
629629
bool m_ExperimentalModeEnabled = false;
630630
bool m_AgilitySDKEnabled = false;
631-
bool m_HLKModeEnabled = false; // Prevent skip logic when running HLK tests.
632631

633632
const float ClearColor[4] = {0.0f, 0.2f, 0.4f, 1.0f};
634633

@@ -672,13 +671,6 @@ class ExecutionTest {
672671
} else {
673672
LogCommentFmt(L"Debug layer enabled.");
674673
}
675-
676-
hr = WEX::TestExecution::RuntimeParameters::TryGetValue(L"HLKModeEnabled",
677-
m_HLKModeEnabled);
678-
679-
if (SUCCEEDED(hr) && m_HLKModeEnabled) {
680-
LogCommentFmt(L"HLK mode enabled.");
681-
}
682674
}
683675

684676
return true;
@@ -11433,6 +11425,9 @@ template <typename T> struct LongVectorOpTestConfig {
1143311425
LongVectorOpTestConfig(LongVectorOpType OpType) : OpType(OpType) {
1143411426
IntrinsicString = "";
1143511427

11428+
if (IsFloatingPointType())
11429+
Tolerance = 1;
11430+
1143611431
switch (OpType) {
1143711432
case LongVectorOpType_ScalarAdd:
1143811433
OperatorString = "+";
@@ -11457,6 +11452,7 @@ template <typename T> struct LongVectorOpTestConfig {
1145711452
IntrinsicString = "max";
1145811453
break;
1145911454
case LongVectorOpType_Clamp:
11455+
OperatorString = ",";
1146011456
IntrinsicString = "TestClamp";
1146111457
IsBinaryOp = false;
1146211458
break;
@@ -11469,6 +11465,12 @@ template <typename T> struct LongVectorOpTestConfig {
1146911465
}
1147011466
}
1147111467

11468+
bool IsFloatingPointType() const {
11469+
return std::is_same_v<T, float> ||
11470+
std::is_same_v<T, double> ||
11471+
std::is_same_v<T, HLSLHalf_t>;
11472+
}
11473+
1147211474
// A helper to get the hlsl type as a string for a given C++ type.
1147311475
// Used in the long vector tests.
1147411476
std::string GetHLSLTypeString() {
@@ -11565,7 +11567,7 @@ template <typename T> class DeterministicNumberGenerator {
1156511567
if constexpr (std::is_same_v<T, int64_t>)
1156611568
return Int64Dist(generator);
1156711569
if constexpr (std::is_same_v<T, float>)
11568-
return FloatDist(generator);
11570+
return FloatDist(generator);
1156911571
if constexpr (std::is_same_v<T, double>)
1157011572
return DoubleDist(generator);
1157111573
if constexpr (std::is_same_v<T, uint16_t>)
@@ -11618,20 +11620,19 @@ bool DoArraysMatch(const std::array<T, N> &ActualValues,
1161811620
} else if constexpr (std::is_same_v<T, HLSLHalf_t>) {
1161911621
const DirectX::PackedVector::HALF a = ActualValues[Index].val;
1162011622
const DirectX::PackedVector::HALF b = ExpectedValues[Index].val;
11621-
if(!CompareHalfULP(a, b, Tolerance))
11622-
{
11623+
if (!CompareHalfULP(a, b, Tolerance)) {
1162311624
MismatchedIndexes.push_back(Index);
1162411625
}
1162511626
} else if constexpr (std::is_same_v<T, float>) {
1162611627
const int IntTolerance = static_cast<int>(Tolerance);
11627-
if(!CompareFloatULP(ActualValues[Index], ExpectedValues[Index], IntTolerance))
11628-
{
11628+
if (!CompareFloatULP(ActualValues[Index], ExpectedValues[Index], IntTolerance)) {
1162911629
MismatchedIndexes.push_back(Index);
1163011630
}
1163111631
} else if constexpr (std::is_same_v<T, double>) {
11632-
WEX::Logging::Log::Warning(L"Double comparison not implemented yet. Defaulting to simple comparison for now.");
11633-
if(ActualValues[Index] != ExpectedValues[Index])
11632+
const int64_t IntTolerance = static_cast<int64_t>(Tolerance);
11633+
if (!CompareDoubleULP(ActualValues[Index], ExpectedValues[Index], IntTolerance)) {
1163411634
MismatchedIndexes.push_back(Index);
11635+
}
1163511636
} else if (Tolerance == 0 && ActualValues[Index] != ExpectedValues[Index]) {
1163611637
MismatchedIndexes.push_back(Index);
1163711638
} else {
@@ -12164,15 +12165,16 @@ void ExecutionTest::LongVectorOpTestBase(
1216412165
if (!CreateDevice(&D3DDevice, D3D_SHADER_MODEL_6_9) &&
1216512166
!m_ExperimentalModeEnabled) {
1216612167

12167-
if (m_HLKModeEnabled) {
12168-
LogErrorFmtThrow(
12169-
L"Device does not support SM 6.9. Can't run these tests.");
12168+
#ifdef _HLK_CONF
12169+
LogErrorFmtThrow(
12170+
L"Device does not support SM 6.9. Can't run these tests.");
1217012171
}
12171-
12172+
#else
1217212173
WEX::Logging::Log::Comment(
1217312174
"Device does not support SM 6.9. Can't run these tests.");
1217412175
WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped);
1217512176
return;
12177+
#endif
1217612178
}
1217712179

1217812180
DeterministicNumberGenerator<T> NumberGenerator(1337);
@@ -12260,25 +12262,30 @@ void ExecutionTest::LongVectorOpTestBase(
1226012262
CompilerOptions << (Is16BitType ? " -enable-16bit-types" : "");
1226112263
CompilerOptions << " -DOPERATOR=";
1226212264
CompilerOptions << TestConfig.OperatorString;
12263-
CompilerOptions << " -DOPERAND2=";
1226412265
if (TestConfig.IsBinaryOp) {
12266+
CompilerOptions << " -DOPERAND2=";
1226512267
CompilerOptions << (TestConfig.IsScalarOp ? "InputScalar" : "InputVector2");
12266-
}
12267-
CompilerOptions << " -DFUNC=";
12268-
CompilerOptions << TestConfig.IntrinsicString;
12269-
switch (TestConfig.OpType) {
12270-
case LongVectorOpType_Clamp:
12271-
CompilerOptions << " -DFUNC_CLAMP=1";
12272-
CompilerOptions << " -DCLAMP_ARGMIN=";
12273-
// We need to set the precision for the float values.
12274-
CompilerOptions << std::setprecision(16);
12275-
CompilerOptions << ClampArgMin;
12276-
CompilerOptions << " -DCLAMP_ARGMAX=";
12277-
CompilerOptions << ClampArgMax;
12278-
break;
12279-
case LongVectorOpType_Initialize:
12280-
CompilerOptions << " -DFUNC_INITIALIZE=1";
12281-
break;
12268+
12269+
if(TestConfig.IsScalarOp) {
12270+
CompilerOptions << " -DIS_SCALAR_OP=1";
12271+
} else {
12272+
CompilerOptions << " -DIS_BINARY_VECTOR_OP=1";
12273+
}
12274+
CompilerOptions << " -DFUNC=";
12275+
CompilerOptions << TestConfig.IntrinsicString;
12276+
} else {
12277+
CompilerOptions << " -DFUNC=";
12278+
CompilerOptions << TestConfig.IntrinsicString;
12279+
CompilerOptions << " -DOPERAND2=";
12280+
switch (TestConfig.OpType) {
12281+
case LongVectorOpType_Clamp:
12282+
CompilerOptions << "ClampArgMinMax";
12283+
CompilerOptions << " -DFUNC_CLAMP=1";
12284+
break;
12285+
case LongVectorOpType_Initialize:
12286+
CompilerOptions << " -DFUNC_INITIALIZE=1";
12287+
break;
12288+
}
1228212289
}
1228312290

1228412291
// We have to construct the string outside of the lambda. Otherwise it's
@@ -12312,10 +12319,13 @@ void ExecutionTest::LongVectorOpTestBase(
1231212319
return;
1231312320
}
1231412321

12315-
// Process the callback for the InputScalar resource.
12316-
if (0 == _stricmp(Name, "InputScalar")) {
12322+
// Process the callback for the InputFuncArgs resource.
12323+
if (0 == _stricmp(Name, "InputFuncArgs")) {
1231712324
if (TestConfig.IsScalarOp) {
1231812325
FillShaderBufferFromLongVectorData<T, 1>(ShaderData, ScalarInput);
12326+
} else if (TestConfig.OpType == LongVectorOpType_Clamp) {
12327+
std::array<T, 2> ClampArgs ={ClampArgMin, ClampArgMax};
12328+
FillShaderBufferFromLongVectorData<T, 2>(ShaderData, ClampArgs);
1231912329
}
1232012330

1232112331
return;

tools/clang/unittests/HLSLExec/ShaderOpArith.xml

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3753,8 +3753,8 @@ void MSMain(uint GID : SV_GroupIndex,
37533753
<ShaderOp Name="LongVectorOp" CS="CS">
37543754
<RootSignature>RootFlags(0), UAV(u0), UAV(u1), UAV(u2),
37553755
UAV(u3)</RootSignature>
3756-
<!-- Width="8" BYTES to account for largest scalar type (64 bits)-->
3757-
<Resource Name="InputScalar" Dimension="BUFFER" Width="8"
3756+
<!-- Width="16" BYTES to account for two largest scalar types (64 bits)-->
3757+
<Resource Name="InputFuncArgs" Dimension="BUFFER" Width="16"
37583758
Flags="ALLOW_UNORDERED_ACCESS" InitialResourceState="COPY_DEST"
37593759
TransitionTo="UNORDERED_ACCESS" Init="ByName" ReadBack="true" />
37603760
<!-- Width="8192" BYTES to account for largest type (64 bits) and vector
@@ -3763,7 +3763,7 @@ void MSMain(uint GID : SV_GroupIndex,
37633763
<Resource Name="InputVector2" Dimension="BUFFER" Width="8192" Flags="ALLOW_UNORDERED_ACCESS" InitialResourceState="COPY_DEST" TransitionTo="UNORDERED_ACCESS" Init="ByName" ReadBack="true" />
37643764
<Resource Name="OutputVector" Dimension="BUFFER" Width="8192" Flags="ALLOW_UNORDERED_ACCESS" InitialResourceState="COPY_DEST" TransitionTo="UNORDERED_ACCESS" Init="ByName" ReadBack="true" />
37653765
<RootValues>
3766-
<RootValue Index="0" ResName="InputScalar" />
3766+
<RootValue Index="0" ResName="InputFuncArgs" />
37673767
<RootValue Index="1" ResName="InputVector1" />
37683768
<RootValue Index="2" ResName="InputVector2" />
37693769
<RootValue Index="3" ResName="OutputVector" />
@@ -3786,21 +3786,38 @@ void MSMain(uint GID : SV_GroupIndex,
37863786
#endif
37873787
37883788
#ifdef FUNC_CLAMP
3789-
vector<TYPE, NUM> TestClamp(vector<TYPE, NUM> Vector)
3789+
vector<TYPE, NUM> TestClamp(vector<TYPE, NUM> Vector, vector<TYPE, 2> ClampArgMinMax)
37903790
{
3791-
return clamp(Vector, TYPE(CLAMP_ARGMIN), TYPE(CLAMP_ARGMAX));
3791+
TYPE ClampArgMin = ClampArgMinMax[0];
3792+
TYPE ClampArgMax = ClampArgMinMax[1];
3793+
return clamp(Vector, ClampArgMin, ClampArgMax);
37923794
}
37933795
#endif
37943796
3795-
RWByteAddressBuffer g_InputScalar : register(u0);
3797+
RWByteAddressBuffer g_InputFuncArgs : register(u0);
37963798
RWByteAddressBuffer g_InputVector1 : register(u1);
37973799
RWByteAddressBuffer g_InputVector2 : register(u2);
37983800
RWByteAddressBuffer g_OutputVector : register(u3);
37993801
[numthreads(1,1,1)]
38003802
void main(uint GI : SV_GroupIndex) {
3801-
vector<TYPE, NUM> InputVector1 = g_InputVector1.Load< vector<TYPE, NUM> >(0);
3802-
vector<TYPE, NUM> InputVector2 = g_InputVector2.Load< vector<TYPE, NUM> >(0);
3803-
TYPE InputScalar = g_InputScalar.Load<TYPE>(0);
3803+
3804+
vector<TYPE, NUM> InputVector1 = g_InputVector1.Load< vector<TYPE,
3805+
NUM> >(0);
3806+
3807+
#ifdef IS_BINARY_VECTOR_OP
3808+
vector<TYPE, NUM> InputVector2 = g_InputVector2.Load< vector<TYPE,
3809+
NUM> >(0);
3810+
#endif
3811+
3812+
#ifdef IS_SCALAR_OP
3813+
TYPE InputScalar = g_InputFuncArgs.Load<TYPE>(0);
3814+
#endif
3815+
3816+
#ifdef FUNC_CLAMP
3817+
TYPE Clamp_ArgMin = g_InputFuncArgs.Load<TYPE>(0);
3818+
TYPE Clamp_ArgMax = g_InputFuncArgs.Load<TYPE>(sizeof(TYPE));
3819+
vector<TYPE, 2> ClampArgMinMax = {Clamp_ArgMin, Clamp_ArgMax};
3820+
#endif
38043821
38053822
vector<TYPE, NUM> OutputVector = FUNC(InputVector1 OPERATOR OPERAND2);
38063823

0 commit comments

Comments
 (0)