Skip to content

Commit 2da0a54

Browse files
authored
Long Vector Execution Tests: Merge unary and binary op tests to main (microsoft#7549)
**Summary** Adds infrastructure for long vector execution tests. This code and additional test cases were already added to the staging-sm6.9 branch. This is the second of several PRs to bring these changes into main. That being said, reviews of this code should treat it as brand new. Resolves microsoft#7545 **Includes:** - A new test class `LongVector::OpTest` in `LongVectors.h/cpp`, still part of the `ExecHLSLTests.dll` binary. - HLSL source added to `ShaderOpArith.xml` to leverage the existing exec test framework for shader compilation and execution. - A new TAEF metadata file `LongVectorOpTable.xml` defining long vector test cases. - `LongVectorTestData.h` for statically defined input values, including `HLSLHalf_t` and `HLSLBool_t`. This avoids duplicating values across test cases. **Template Handling** To support template instantiation across translation units, `LongVectors.tpp` contains full template definitions included by `LongVectors.h`. These were originally required when tests lived in `ExecutionTests.cpp`. Now that the tests are isolated, the plan is to move the definitions back into `LongVectors.cpp` after merging the long vector tests from `staging-sm6.9` to simplify the manual merge. **Utilities** `HlslTestUtils.h` includes minor updates to support the new test scenarios.
1 parent 7e0d771 commit 2da0a54

File tree

9 files changed

+1819
-10
lines changed

9 files changed

+1819
-10
lines changed

include/dxc/Test/HlslTestUtils.h

Lines changed: 86 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,29 @@ inline void LogErrorFmt(const wchar_t *fmt, ...) {
260260
WEX::Logging::Log::Error(buf.data());
261261
}
262262

263+
inline void LogErrorFmtThrow(const char *fileName, int line, const wchar_t *fmt,
264+
...) {
265+
va_list args;
266+
va_start(args, fmt);
267+
std::wstring buf(vFormatToWString(fmt, args));
268+
va_end(args);
269+
270+
std::wstringstream wss;
271+
wss << L"Error in file: " << fileName << L" at line: " << line << L"\n"
272+
<< buf.data() << L"\n"
273+
<< buf;
274+
275+
WEX::Logging::Log::Error(wss.str().c_str());
276+
277+
// Throws an exception to abort the test.
278+
VERIFY_FAIL(L"Test error");
279+
}
280+
281+
// Macro to pass the file name and line number. Otherwise TAEF prints this file
282+
// and line number.
283+
#define LOG_ERROR_FMT_THROW(fmt, ...) \
284+
hlsl_test::LogErrorFmtThrow(__FILE__, __LINE__, fmt, __VA_ARGS__)
285+
263286
inline std::wstring
264287
GetPathToHlslDataFile(const wchar_t *relative,
265288
LPCWSTR paramName = HLSLDATAFILEPARAM,
@@ -461,15 +484,17 @@ inline bool GetTestParamUseWARP(bool defaultVal) {
461484

462485
#ifdef FP_SUBNORMAL
463486

464-
inline bool isdenorm(float f) { return FP_SUBNORMAL == std::fpclassify(f); }
487+
template <typename T> inline bool isdenorm(T f) {
488+
return FP_SUBNORMAL == std::fpclassify(f);
489+
}
465490

466491
#else
467492

468-
inline bool isdenorm(float f) {
469-
return (std::numeric_limits<float>::denorm_min() <= f &&
470-
f < std::numeric_limits<float>::min()) ||
471-
(-std::numeric_limits<float>::min() < f &&
472-
f <= -std::numeric_limits<float>::denorm_min());
493+
template <typename T> inline bool isdenorm(T f) {
494+
return (std::numeric_limits<T>::denorm_min() <= f &&
495+
f < std::numeric_limits<T>::min()) ||
496+
(-std::numeric_limits<T>::min() < f &&
497+
f <= -std::numeric_limits<T>::denorm_min());
473498
}
474499

475500
#endif // FP_SUBNORMAL
@@ -517,6 +542,44 @@ inline bool isnanFloat16(uint16_t val) {
517542
uint16_t ConvertFloat32ToFloat16(float val) throw();
518543
float ConvertFloat16ToFloat32(uint16_t val) throw();
519544

545+
inline bool CompareDoubleULP(
546+
const double &Src, const double &Ref, int64_t ULPTolerance,
547+
hlsl::DXIL::Float32DenormMode Mode = hlsl::DXIL::Float32DenormMode::Any) {
548+
if (Src == Ref) {
549+
return true;
550+
}
551+
if (std::isnan(Src)) {
552+
return std::isnan(Ref);
553+
}
554+
555+
if (Mode == hlsl::DXIL::Float32DenormMode::Any) {
556+
// If denorm expected, output can be sign preserved zero. Otherwise output
557+
// should pass the regular ulp testing.
558+
if (isdenorm(Ref) && Src == 0 && std::signbit(Src) == std::signbit(Ref))
559+
return true;
560+
}
561+
562+
// For FTZ or Preserve mode, we should get the expected number within
563+
// ULPTolerance for any operations.
564+
int64_t Diff = *((const uint64_t *)&Src) - *((const uint64_t *)&Ref);
565+
566+
uint64_t AbsoluteDiff = Diff < 0 ? -Diff : Diff;
567+
return AbsoluteDiff <= (uint64_t)ULPTolerance;
568+
}
569+
570+
inline bool CompareDoubleEpsilon(const double &Src, const double &Ref,
571+
float Epsilon) {
572+
if (Src == Ref) {
573+
return true;
574+
}
575+
if (std::isnan(Src)) {
576+
return std::isnan(Ref);
577+
}
578+
// For FTZ or Preserve mode, we should get the expected number within
579+
// epsilon for any operations.
580+
return fabs(Src - Ref) < Epsilon;
581+
}
582+
520583
inline bool CompareFloatULP(
521584
const float &fsrc, const float &fref, int ULPTolerance,
522585
hlsl::DXIL::Float32DenormMode mode = hlsl::DXIL::Float32DenormMode::Any) {
@@ -568,12 +631,26 @@ inline bool CompareFloatRelativeEpsilon(
568631

569632
inline bool CompareHalfULP(const uint16_t &fsrc, const uint16_t &fref,
570633
float ULPTolerance) {
634+
// Treat +0 and -0 as equal
635+
if ((fsrc & ~FLOAT16_BIT_SIGN) == 0 && (fref & ~FLOAT16_BIT_SIGN) == 0)
636+
return true;
571637
if (fsrc == fref)
572638
return true;
573-
if (isnanFloat16(fsrc))
574-
return isnanFloat16(fref);
639+
640+
const bool nanRef = isnanFloat16(fref);
641+
const bool nanSrc = isnanFloat16(fsrc);
642+
if (nanRef || nanSrc)
643+
return nanRef && nanSrc;
644+
645+
// Map to monotonic ordering for correct ULP diff
646+
auto toOrdered = [](uint16_t h) -> int {
647+
return (h & FLOAT16_BIT_SIGN) ? (~h & 0xFFFF) : (h | 0x8000);
648+
};
649+
575650
// 16-bit floating point numbers must preserve denorms
576-
int diff = fsrc - fref;
651+
int i_fsrc = toOrdered(fsrc);
652+
int i_fref = toOrdered(fref);
653+
int diff = i_fsrc - i_fref;
577654
unsigned int uDiff = diff < 0 ? -diff : diff;
578655
return uDiff <= (unsigned int)ULPTolerance;
579656
}

tools/clang/unittests/HLSLExec/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ add_clang_library(ExecHLSLTests SHARED
99
ExecutionTest.cpp
1010
ShaderOpTest.cpp
1111
TableParameterHandler.cpp
12+
LongVectors.cpp
1213
ExecHLSLTests.rc
1314
)
1415

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
#include <windows.h>
22

3-
ShaderOpArithTable.xml DATASOURCE_XML "ShaderOpArithTable.xml"
3+
ShaderOpArithTable.xml DATASOURCE_XML "ShaderOpArithTable.xml"
4+
LongVectorOpTable.xml DATASOURCE_XML "LongVectorOpTable.xml"

0 commit comments

Comments
 (0)