Skip to content

Commit 09bc6cb

Browse files
committed
Change validation config to use double instead of float. Higher precision.
1 parent a5fa085 commit 09bc6cb

2 files changed

Lines changed: 20 additions & 48 deletions

File tree

include/dxc/Test/HlslTestUtils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ inline bool CompareDoubleULP(
580580
}
581581

582582
inline bool CompareDoubleEpsilon(const double &Src, const double &Ref,
583-
float Epsilon) {
583+
double Epsilon) {
584584
if (Src == Ref) {
585585
return true;
586586
}

tools/clang/unittests/HLSLExec/LongVectors.cpp

Lines changed: 19 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -176,37 +176,37 @@ enum class ValidationType {
176176
};
177177

178178
template <typename T>
179-
bool doValuesMatch(T A, T B, float Tolerance, ValidationType) {
180-
if (Tolerance == 0.0f)
179+
bool doValuesMatch(T A, T B, double Tolerance, ValidationType) {
180+
if (Tolerance == 0.0)
181181
return A == B;
182182

183183
T Diff = A > B ? A - B : B - A;
184184
return Diff <= Tolerance;
185185
}
186186

187-
bool doValuesMatch(HLSLBool_t A, HLSLBool_t B, float, ValidationType) {
187+
bool doValuesMatch(HLSLBool_t A, HLSLBool_t B, double, ValidationType) {
188188
return A == B;
189189
}
190190

191-
bool doValuesMatch(HLSLHalf_t A, HLSLHalf_t B, float Tolerance,
191+
bool doValuesMatch(HLSLHalf_t A, HLSLHalf_t B, double Tolerance,
192192
ValidationType ValidationType) {
193193
switch (ValidationType) {
194194
case ValidationType::Epsilon:
195-
return CompareHalfEpsilon(A.Val, B.Val, Tolerance);
195+
return CompareHalfEpsilon(A.Val, B.Val, static_cast<float>(Tolerance));
196196
case ValidationType::Ulp:
197-
return CompareHalfULP(A.Val, B.Val, Tolerance);
197+
return CompareHalfULP(A.Val, B.Val, static_cast<float>(Tolerance));
198198
default:
199199
hlsl_test::LogErrorFmt(
200200
L"Invalid ValidationType. Expecting Epsilon or ULP.");
201201
return false;
202202
}
203203
}
204204

205-
bool doValuesMatch(float A, float B, float Tolerance,
205+
bool doValuesMatch(float A, float B, double Tolerance,
206206
ValidationType ValidationType) {
207207
switch (ValidationType) {
208208
case ValidationType::Epsilon:
209-
return CompareFloatEpsilon(A, B, Tolerance);
209+
return CompareFloatEpsilon(A, B, static_cast<float>(Tolerance));
210210
case ValidationType::Ulp: {
211211
// Tolerance is in ULPs. Convert to int for the comparison.
212212
const int IntTolerance = static_cast<int>(Tolerance);
@@ -219,7 +219,7 @@ bool doValuesMatch(float A, float B, float Tolerance,
219219
}
220220
}
221221

222-
bool doValuesMatch(double A, double B, float Tolerance,
222+
bool doValuesMatch(double A, double B, double Tolerance,
223223
ValidationType ValidationType) {
224224
switch (ValidationType) {
225225
case ValidationType::Epsilon:
@@ -238,7 +238,7 @@ bool doValuesMatch(double A, double B, float Tolerance,
238238

239239
template <typename T>
240240
bool doVectorsMatch(const std::vector<T> &ActualValues,
241-
const std::vector<T> &ExpectedValues, float Tolerance,
241+
const std::vector<T> &ExpectedValues, double Tolerance,
242242
ValidationType ValidationType, bool VerboseLogging) {
243243

244244
DXASSERT(
@@ -540,14 +540,14 @@ InputSets<T> buildTestInputs(size_t VectorSize, const InputSet OpInputSets[3],
540540
}
541541

542542
struct ValidationConfig {
543-
float Tolerance = 0.0f;
543+
double Tolerance = 0.0;
544544
ValidationType Type = ValidationType::Epsilon;
545545

546-
static ValidationConfig Epsilon(float Tolerance) {
546+
static ValidationConfig Epsilon(double Tolerance) {
547547
return ValidationConfig{Tolerance, ValidationType::Epsilon};
548548
}
549549

550-
static ValidationConfig Ulp(float Tolerance) {
550+
static ValidationConfig Ulp(double Tolerance) {
551551
return ValidationConfig{Tolerance, ValidationType::Ulp};
552552
}
553553
};
@@ -943,8 +943,7 @@ struct Op<OpType::AsUint_SplitDouble, double, 1> : StrictValidation {};
943943
template <> struct ExpectedBuilder<OpType::AsUint_SplitDouble, double> {
944944
static std::vector<uint32_t>
945945
buildExpected(Op<OpType::AsUint_SplitDouble, double, 1> &,
946-
const InputSets<double> &Inputs, uint16_t ScalarInputFlags) {
947-
DXASSERT_NOMSG(ScalarInputFlags == 0);
946+
const InputSets<double> &Inputs) {
948947
DXASSERT_NOMSG(Inputs.size() == 1);
949948

950949
size_t VectorSize = Inputs[0].size();
@@ -1018,8 +1017,7 @@ template <> struct Op<OpType::Frexp, float, 1> : DefaultValidation<float> {};
10181017

10191018
template <> struct ExpectedBuilder<OpType::Frexp, float> {
10201019
static std::vector<float> buildExpected(Op<OpType::Frexp, float, 1> &,
1021-
const InputSets<float> &Inputs,
1022-
uint32_t) {
1020+
const InputSets<float> &Inputs) {
10231021
DXASSERT_NOMSG(Inputs.size() == 1);
10241022

10251023
// Expected values size is doubled. In the first half we store the
@@ -1089,7 +1087,7 @@ OP_3(OpType::Select, StrictValidation, (static_cast<bool>(A) ? B : C));
10891087
template <typename T> struct Op<OP, T, 1> : StrictValidation {}; \
10901088
template <typename T> struct ExpectedBuilder<OP, T> { \
10911089
static std::vector<HLSLBool_t> \
1092-
buildExpected(Op<OP, T, 1> &, const InputSets<T> &Inputs, uint16_t) { \
1090+
buildExpected(Op<OP, T, 1> &, const InputSets<T> &Inputs) { \
10931091
const bool Res = STDFUNC(Inputs[0].begin(), Inputs[0].end(), \
10941092
[](T A) { return A != static_cast<T>(0); }); \
10951093
return std::vector<HLSLBool_t>{Res}; \
@@ -1115,9 +1113,7 @@ template <typename T> struct ExpectedBuilder<OpType::Dot, T> {
11151113
// worst-case sequence, then summing the per-step epsilons to produce a
11161114
// conservative error tolerance for the entire Dot operation.
11171115
static std::vector<T> buildExpected(Op<OpType::Dot, T, 2> &Op,
1118-
const InputSets<T> &Inputs,
1119-
uint16_t ScalarInputFlags) {
1120-
UNREFERENCED_PARAMETER(ScalarInputFlags);
1116+
const InputSets<T> &Inputs) {
11211117

11221118
std::vector<double> PositiveProducts;
11231119
std::vector<double> NegativeProducts;
@@ -1126,7 +1122,7 @@ template <typename T> struct ExpectedBuilder<OpType::Dot, T> {
11261122

11271123
// Floating point ops have a tolerance of 0.5 ULPs per operation as per the
11281124
// DX spec.
1129-
const float ULPTolerance = 0.5f;
1125+
const double ULPTolerance = 0.5;
11301126

11311127
// Accumulate in fp64 to improve precision.
11321128
double DotProduct = 0.0; // computed reference result
@@ -1179,7 +1175,7 @@ template <typename T> struct ExpectedBuilder<OpType::Dot, T> {
11791175
};
11801176

11811177
template <typename T>
1182-
static double computeAbsoluteEpsilon(double A, float ULPTolerance) {
1178+
static double computeAbsoluteEpsilon(double A, double ULPTolerance) {
11831179
DXASSERT((!isinf(A) && !isnan(A)),
11841180
"Input values should not produce inf or nan results");
11851181

@@ -1226,30 +1222,6 @@ STRICT_OP_1(OpType::LoadAndStore_DT_SB_SRV, (A));
12261222
STRICT_OP_1(OpType::LoadAndStore_RD_SB_UAV, (A));
12271223
STRICT_OP_1(OpType::LoadAndStore_RD_SB_SRV, (A));
12281224

1229-
static double computeAbsoluteEpsilon(double A, float ULPTolerance)
1230-
{
1231-
if(isinf(A) || isnan(A))
1232-
static double computeAbsoluteEpsilon(double A, float ULPTolerance) {
1233-
if (isinf(A) || isnan(A))
1234-
// None of the existing input values should produce inf or nan results.
1235-
DXASSERT_NOMSG(false);
1236-
1237-
// ULP is a positive value by definition. So, working with abs(A) simplifies
1238-
// our logic for computing ULP in the first place.
1239-
A = std::abs(A);
1240-
1241-
double ULP = 0.0;
1242-
1243-
if constexpr (std::is_same_v<T, HLSLHalf_t>)
1244-
ULP = HLSLHalf_t::GetULP(A);
1245-
else
1246-
ULP =
1247-
std::nextafter(static_cast<T>(A), std::numeric_limits<T>::infinity()) -
1248-
static_cast<T>(A);
1249-
1250-
return ULP * ULPTolerance;
1251-
}
1252-
12531225
//
12541226
// dispatchTest
12551227
//

0 commit comments

Comments
 (0)