From 6f61d35a2c03c495391be6839d3900d4dd14de93 Mon Sep 17 00:00:00 2001 From: Alex Sepkowski <5620315+alsepkow@users.noreply.github.com> Date: Wed, 19 Nov 2025 15:57:49 -0800 Subject: [PATCH 01/10] Partial derivatives added --- .../unittests/HLSLExec/LongVectorOps.def | 21 ++++++- .../clang/unittests/HLSLExec/LongVectors.cpp | 56 ++++++++++++++++++- .../unittests/HLSLExec/ShaderOpArith.xml | 34 +++++++++-- 3 files changed, 103 insertions(+), 8 deletions(-) diff --git a/tools/clang/unittests/HLSLExec/LongVectorOps.def b/tools/clang/unittests/HLSLExec/LongVectorOps.def index f3908ff055..edc8b6d74d 100644 --- a/tools/clang/unittests/HLSLExec/LongVectorOps.def +++ b/tools/clang/unittests/HLSLExec/LongVectorOps.def @@ -66,7 +66,7 @@ OP_DEFAULT_DEFINES(Unary, Initialize, 1, "TestInitialize", "", #define OP_CAST_DEFAULT(GROUP, SYMBOL) \ OP_DEFAULT_DEFINES(GROUP, SYMBOL, 1, "TestCast", "", "-DFUNC_TEST_CAST=1") #define OP_CAST(GROUP, SYMBOL, INPUT_SET_1) \ - OP(GROUP, SYMBOL, 1, "TestCast", "", "-DFUNC_TEST_CAST=1", "LongVectorOP", \ + OP(GROUP, SYMBOL, 1, "TestCast", "", "-DFUNC_TEST_CAST=1", "LongVectorOp", \ INPUT_SET_1, Default2, Default3) OP_CAST_DEFAULT(Cast, CastToBool) @@ -205,7 +205,22 @@ OP_DEFAULT_DEFINES(Wave, WaveActiveBitXor, 1, "TestWaveActiveBitXor", "", " -DFU OP_DEFAULT_DEFINES(Wave, WaveActiveAllEqual, 1, "TestWaveActiveAllEqual", "", " -DFUNC_WAVE_ACTIVE_ALL_EQUAL=1") OP_DEFAULT_DEFINES(Wave, WaveReadLaneAt, 1, "TestWaveReadLaneAt", "", " -DFUNC_WAVE_READ_LANE_AT=1") OP_DEFAULT_DEFINES(Wave, WaveReadLaneFirst, 1, "TestWaveReadLaneFirst", "", " -DFUNC_WAVE_READ_LANE_FIRST=1") -OP_DEFAULT_DEFINES(Wave, WavePrefixSum, 1, "TestWavePrefixSum", "", " -DFUNC_WAVE_PREFIX_SUM=1 -DIS_WAVE_PREFIX_OP=1") -OP_DEFAULT_DEFINES(Wave, WavePrefixProduct, 1, "TestWavePrefixProduct", "", " -DFUNC_WAVE_PREFIX_PRODUCT=1 -DIS_WAVE_PREFIX_OP=1") +OP_DEFAULT_DEFINES(Wave, WavePrefixSum, 1, "TestWavePrefixSum", "", " -DFUNC_WAVE_PREFIX_SUM=1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1") +OP_DEFAULT_DEFINES(Wave, WavePrefixProduct, 1, "TestWavePrefixProduct", "", " -DFUNC_WAVE_PREFIX_PRODUCT=1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1") + +// NOTE: Default2 is used as the input set because Default1 can have precision +// issues with half types in derivative calculations. +#define OP_DERIVATIVE(GROUP, SYMBOL, DERIVATIVE_INTRINSIC) \ + OP(GROUP, SYMBOL, 1, "TestDerivative", "", "-DFUNC_TEST_DERIVATIVE=1 \ + -DNUMTHREADS_XYZ=2,2,1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1 \ + -DDERIVATIVE_FUNC=" DERIVATIVE_INTRINSIC, "LongVectorOp", Default2, \ + Default1, Default3) + +OP_DERIVATIVE(Derivative, DerivativeDdx, "ddx") +OP_DERIVATIVE(Derivative, DerivativeDdy, "ddy") +OP_DERIVATIVE(Derivative, DerivativeDdxFine, "ddx_fine") +OP_DERIVATIVE(Derivative, DerivativeDdyFine, "ddy_fine") + +#undef OP_DERIVATIVE #undef OP diff --git a/tools/clang/unittests/HLSLExec/LongVectors.cpp b/tools/clang/unittests/HLSLExec/LongVectors.cpp index 5ab16b75a8..0245ad522a 100644 --- a/tools/clang/unittests/HLSLExec/LongVectors.cpp +++ b/tools/clang/unittests/HLSLExec/LongVectors.cpp @@ -1296,6 +1296,48 @@ template struct ExpectedBuilder { } }; +// +// Derivative Ops +// + +// Coarse derivative ops return the same partial derivative value for all lanes +// in the quad. +// Top right (lane 1) - Top Left (lane 0) +DEFAULT_OP_1(OpType::DerivativeDdx, ((A + 2) - (A + 0))); +// Lower left (lane 2) - Top Left (lane 0) +DEFAULT_OP_1(OpType::DerivativeDdy, ((A + 4) - (A + 0))); + +// Fine derivative ops return different partial derivative values for each +DEFAULT_OP_1(OpType::DerivativeDdxFine, ((A + 2) - (A + 0))); +// Lower left (lane 2) - Top Left (lane 0) +DEFAULT_OP_1(OpType::DerivativeDdyFine, ((A + 4) - (A + 0))); + +// template +// struct Op : DefaultValidation{}; +// +// template struct ExpectedBuilder { +// static std::vector +// buildExpected(Op &, +// const InputSets &Inputs) { +// DXASSERT_NOMSG(Inputs.size() == 1); +// +// std::vector Expected; +// const size_t VectorSize = Inputs[0].size(); +// Expected.resize(VectorSize); +// +// // Coarse derivative always does top right minus top left. That is, lane +// 1 +// // minus lane 0. And we do A + LaneID*2 in each lane. +// for(size_t I = 0; I < VectorSize; ++I) +// { +// const T A = Inputs[0][I]; +// Expected[I] = (A+2) - (A+0); +// } +// +// return Expected; +// } +// }; + // // Wave Ops // @@ -1548,7 +1590,7 @@ void dispatchWaveOpTest(ID3D12Device *D3DDevice, bool VerboseLogging, const std::string AdditionalCompilerOptions = "-DWAVE_SIZE=" + std::to_string(WaveSize) + - " -DNUMTHREADS_X=" + std::to_string(WaveSize); + " -DNUMTHREADS_XYZ=" + std::to_string(WaveSize) + ",1,1 "; for (size_t VectorSize : InputVectorSizes) { std::vector> Inputs = @@ -2330,6 +2372,18 @@ class DxilConf_SM69_Vectorized { HLK_TEST(LoadAndStore_RD_SB_SRV, double); HLK_TEST(LoadAndStore_RD_SB_UAV, double); + // Derivative + HLK_TEST(DerivativeDdx, HLSLHalf_t); + HLK_TEST(DerivativeDdy, HLSLHalf_t); + HLK_TEST(DerivativeDdxFine, HLSLHalf_t); + HLK_TEST(DerivativeDdyFine, HLSLHalf_t); + HLK_TEST(DerivativeDdx, float); + HLK_TEST(DerivativeDdy, float); + HLK_TEST(DerivativeDdxFine, float); + HLK_TEST(DerivativeDdyFine, float); + + // Wave + HLK_WAVEOP_TEST(WaveActiveAllEqual, HLSLBool_t); HLK_WAVEOP_TEST(WaveReadLaneAt, HLSLBool_t); HLK_WAVEOP_TEST(WaveReadLaneFirst, HLSLBool_t); diff --git a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml index 5bc9f7118e..8ad458faf7 100644 --- a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml +++ b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml @@ -4247,8 +4247,35 @@ void MSMain(uint GID : SV_GroupIndex, } #endif - #ifdef NUMTHREADS_X - #define NUMTHREADS_ATTR [numthreads(NUMTHREADS_X, 1, 1)] + #ifdef FUNC_TEST_DERIVATIVE + void TestDerivative(vector Vector) + { + // 0 == upper-left lane in quad + // 1 == upper-right lane in quad + // 2 == lower-left lane in quad + // 3 == lower-right lane in quad + + const uint LaneIndex = WaveGetLaneIndex(); + + // Need to make the values unique across lanes so we can get a + // non-zero partial derivative. + Vector += ((TYPE)(LaneIndex * 2)); + + vector Result = DERIVATIVE_FUNC(Vector); + + // For coarse derivatives, all lanes in the quad get the same result. + // But for fine derivatives, each lane gets a different result. To + // keep things simple we only store in the third lane as thats the + // lane we arbitrarily chose for validation with fine derivatives. + if(LaneIndex == 3) + { + g_OutputVector.Store< vector >(0, Result); + } + } + #endif + + #ifdef NUMTHREADS_XYZ + #define NUMTHREADS_ATTR [numthreads(NUMTHREADS_XYZ)] #else #define NUMTHREADS_ATTR [numthreads(1, 1, 1)] #endif @@ -4289,8 +4316,7 @@ void MSMain(uint GID : SV_GroupIndex, #endif vector OutputVector; - #ifdef IS_WAVE_PREFIX_OP - // Wave prefix ops store the output on a specific lane only. + #ifdef OP_STORES_RESULT_ON_SPECIFIC_LANE FUNC(Input1); return; #elif IS_UNARY_OP From 049f7a23928169939a4e51886d7fb64ee86a8f87 Mon Sep 17 00:00:00 2001 From: Alex Sepkowski <5620315+alsepkow@users.noreply.github.com> Date: Wed, 19 Nov 2025 17:40:20 -0800 Subject: [PATCH 02/10] Revert non related change --- tools/clang/unittests/HLSLExec/LongVectorOps.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/clang/unittests/HLSLExec/LongVectorOps.def b/tools/clang/unittests/HLSLExec/LongVectorOps.def index edc8b6d74d..5d230231d7 100644 --- a/tools/clang/unittests/HLSLExec/LongVectorOps.def +++ b/tools/clang/unittests/HLSLExec/LongVectorOps.def @@ -66,7 +66,7 @@ OP_DEFAULT_DEFINES(Unary, Initialize, 1, "TestInitialize", "", #define OP_CAST_DEFAULT(GROUP, SYMBOL) \ OP_DEFAULT_DEFINES(GROUP, SYMBOL, 1, "TestCast", "", "-DFUNC_TEST_CAST=1") #define OP_CAST(GROUP, SYMBOL, INPUT_SET_1) \ - OP(GROUP, SYMBOL, 1, "TestCast", "", "-DFUNC_TEST_CAST=1", "LongVectorOp", \ + OP(GROUP, SYMBOL, 1, "TestCast", "", "-DFUNC_TEST_CAST=1", "LongVectorOP", \ INPUT_SET_1, Default2, Default3) OP_CAST_DEFAULT(Cast, CastToBool) From 55f260a0256fdc89f0d05945e7177e61ee1414ca Mon Sep 17 00:00:00 2001 From: Alex Sepkowski <5620315+alsepkow@users.noreply.github.com> Date: Wed, 19 Nov 2025 19:11:54 -0800 Subject: [PATCH 03/10] QuadReadLaneAt. Half not working? --- .../unittests/HLSLExec/LongVectorOps.def | 3 ++ .../clang/unittests/HLSLExec/LongVectors.cpp | 53 ++++++++++--------- .../unittests/HLSLExec/ShaderOpArith.xml | 21 ++++++++ 3 files changed, 52 insertions(+), 25 deletions(-) diff --git a/tools/clang/unittests/HLSLExec/LongVectorOps.def b/tools/clang/unittests/HLSLExec/LongVectorOps.def index 5d230231d7..adc5040945 100644 --- a/tools/clang/unittests/HLSLExec/LongVectorOps.def +++ b/tools/clang/unittests/HLSLExec/LongVectorOps.def @@ -223,4 +223,7 @@ OP_DERIVATIVE(Derivative, DerivativeDdyFine, "ddy_fine") #undef OP_DERIVATIVE +OP_DEFAULT_DEFINES(Quad, QuadReadLaneAt, 1, "TestQuadReadLaneAt", "", + " -DFUNC_TEST_QUAD_READ_LANE_AT=1 -DNUMTHREADS_XYZ=2,2,1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1") + #undef OP diff --git a/tools/clang/unittests/HLSLExec/LongVectors.cpp b/tools/clang/unittests/HLSLExec/LongVectors.cpp index 0245ad522a..198d0220fe 100644 --- a/tools/clang/unittests/HLSLExec/LongVectors.cpp +++ b/tools/clang/unittests/HLSLExec/LongVectors.cpp @@ -1312,31 +1312,23 @@ DEFAULT_OP_1(OpType::DerivativeDdxFine, ((A + 2) - (A + 0))); // Lower left (lane 2) - Top Left (lane 0) DEFAULT_OP_1(OpType::DerivativeDdyFine, ((A + 4) - (A + 0))); -// template -// struct Op : DefaultValidation{}; -// -// template struct ExpectedBuilder { -// static std::vector -// buildExpected(Op &, -// const InputSets &Inputs) { -// DXASSERT_NOMSG(Inputs.size() == 1); -// -// std::vector Expected; -// const size_t VectorSize = Inputs[0].size(); -// Expected.resize(VectorSize); -// -// // Coarse derivative always does top right minus top left. That is, lane -// 1 -// // minus lane 0. And we do A + LaneID*2 in each lane. -// for(size_t I = 0; I < VectorSize; ++I) -// { -// const T A = Inputs[0][I]; -// Expected[I] = (A+2) - (A+0); -// } -// -// return Expected; -// } -// }; +template +struct Op : DefaultValidation {}; + +template struct ExpectedBuilder { + static std::vector buildExpected(Op &, + const InputSets &Inputs) { + DXASSERT_NOMSG(Inputs.size() == 1); + + std::vector Expected; + const size_t VectorSize = Inputs[0].size(); + // As a simple test, we arbitrarily pick the 3rd element to fill the vector + // on a single lane. And then read from it on another lane. + Expected.assign(VectorSize, Inputs[0][2]); + + return Expected; + } +}; // // Wave Ops @@ -2382,6 +2374,17 @@ class DxilConf_SM69_Vectorized { HLK_TEST(DerivativeDdxFine, float); HLK_TEST(DerivativeDdyFine, float); + // Quad + HLK_TEST(QuadReadLaneAt, HLSLBool_t); + HLK_TEST(QuadReadLaneAt, int16_t); + HLK_TEST(QuadReadLaneAt, int32_t); + HLK_TEST(QuadReadLaneAt, int64_t); + HLK_TEST(QuadReadLaneAt, uint16_t); + HLK_TEST(QuadReadLaneAt, uint32_t); + HLK_TEST(QuadReadLaneAt, uint64_t); + HLK_TEST(QuadReadLaneAt, float); + HLK_TEST(QuadReadLaneAt, HLSLHalf_t); + // Wave HLK_WAVEOP_TEST(WaveActiveAllEqual, HLSLBool_t); diff --git a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml index 8ad458faf7..12b1b04bae 100644 --- a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml +++ b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml @@ -4274,6 +4274,27 @@ void MSMain(uint GID : SV_GroupIndex, } #endif + #ifdef FUNC_TEST_QUAD_READ_LANE_AT + void TestQuadReadLaneAt(vector Vector) + { + const uint LaneIndex = WaveGetLaneIndex(); + + // Arbitrarily fill the vector with something different on lane 2. + [unroll] + for(uint i = 0; i < NUM; ++i) + { + Vector[i] = (LaneIndex == 2) ? Vector[2] : Vector[i]; + } + + vector Result = QuadReadLaneAt(Vector, 2); + + if(LaneIndex == 3) + { + g_OutputVector.Store< vector >(0, Result); + } + } + #endif + #ifdef NUMTHREADS_XYZ #define NUMTHREADS_ATTR [numthreads(NUMTHREADS_XYZ)] #else From 8760194be2e677d8055d5c441d2982d0ba2d8a43 Mon Sep 17 00:00:00 2001 From: Alex Sepkowski <5620315+alsepkow@users.noreply.github.com> Date: Thu, 20 Nov 2025 14:44:08 -0800 Subject: [PATCH 04/10] QuadReadAcross*. Need to cleanup --- .../unittests/HLSLExec/LongVectorOps.def | 7 +- .../clang/unittests/HLSLExec/LongVectors.cpp | 88 ++++++++++++++++++- .../unittests/HLSLExec/ShaderOpArith.xml | 68 ++++++++++++++ 3 files changed, 161 insertions(+), 2 deletions(-) diff --git a/tools/clang/unittests/HLSLExec/LongVectorOps.def b/tools/clang/unittests/HLSLExec/LongVectorOps.def index adc5040945..0b23ec4a10 100644 --- a/tools/clang/unittests/HLSLExec/LongVectorOps.def +++ b/tools/clang/unittests/HLSLExec/LongVectorOps.def @@ -225,5 +225,10 @@ OP_DERIVATIVE(Derivative, DerivativeDdyFine, "ddy_fine") OP_DEFAULT_DEFINES(Quad, QuadReadLaneAt, 1, "TestQuadReadLaneAt", "", " -DFUNC_TEST_QUAD_READ_LANE_AT=1 -DNUMTHREADS_XYZ=2,2,1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1") - +OP_DEFAULT_DEFINES(Quad, QuadReadAcrossX, 1, "TestQuadReadAcrossX", "", + " -DFUNC_TEST_QUAD_READ_ACROSS_X=1 -DNUMTHREADS_XYZ=2,2,1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1") +OP_DEFAULT_DEFINES(Quad, QuadReadAcrossY, 1, "TestQuadReadAcrossY", "", + " -DFUNC_TEST_QUAD_READ_ACROSS_Y=1 -DNUMTHREADS_XYZ=2,2,1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1") +OP_DEFAULT_DEFINES(Quad, QuadReadAcrossDiagonal, 1, "TestQuadReadAcrossDiagonal", "", + " -DFUNC_TEST_QUAD_READ_ACROSS_DIAGONAL=1 -DNUMTHREADS_XYZ=2,2,1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1") #undef OP diff --git a/tools/clang/unittests/HLSLExec/LongVectors.cpp b/tools/clang/unittests/HLSLExec/LongVectors.cpp index 198d0220fe..df04ab5343 100644 --- a/tools/clang/unittests/HLSLExec/LongVectors.cpp +++ b/tools/clang/unittests/HLSLExec/LongVectors.cpp @@ -1330,6 +1330,61 @@ template struct ExpectedBuilder { } }; +template +struct Op : DefaultValidation {}; + +template struct ExpectedBuilder { + static std::vector buildExpected(Op &, + const InputSets &Inputs) { + DXASSERT_NOMSG(Inputs.size() == 1); + + std::vector Expected; + const size_t VectorSize = Inputs[0].size(); + // As a simple test, we arbitrarily pick the 3rd element to fill the vector + // on another lane in this quad in the X direction. + Expected.assign(VectorSize, Inputs[0][2]); + + return Expected; + } +}; + +template +struct Op : DefaultValidation {}; + +template struct ExpectedBuilder { + static std::vector buildExpected(Op &, + const InputSets &Inputs) { + DXASSERT_NOMSG(Inputs.size() == 1); + + std::vector Expected; + const size_t VectorSize = Inputs[0].size(); + // As a simple test, we arbitrarily pick the 3rd element to fill the vector + // on another lane in this quad in the Y direction. + Expected.assign(VectorSize, Inputs[0][2]); + + return Expected; + } +}; + +template +struct Op : DefaultValidation {}; + +template struct ExpectedBuilder { + static std::vector buildExpected(Op &, + const InputSets &Inputs) { + DXASSERT_NOMSG(Inputs.size() == 1); + + std::vector Expected; + const size_t VectorSize = Inputs[0].size(); + // As a simple test, we arbitrarily pick the 3rd element to fill the vector + // on another lane in this quad in the Y direction. + Expected.assign(VectorSize, Inputs[0][2]); + + return Expected; + } +}; + + // // Wave Ops // @@ -2376,14 +2431,45 @@ class DxilConf_SM69_Vectorized { // Quad HLK_TEST(QuadReadLaneAt, HLSLBool_t); + HLK_TEST(QuadReadAcrossX, HLSLBool_t); + HLK_TEST(QuadReadAcrossY, HLSLBool_t); + HLK_TEST(QuadReadAcrossDiagonal, HLSLBool_t); HLK_TEST(QuadReadLaneAt, int16_t); + HLK_TEST(QuadReadAcrossX, int16_t); + HLK_TEST(QuadReadAcrossY, int16_t); + HLK_TEST(QuadReadAcrossDiagonal, int16_t); HLK_TEST(QuadReadLaneAt, int32_t); + HLK_TEST(QuadReadAcrossX, int32_t); + HLK_TEST(QuadReadAcrossY, int32_t); + HLK_TEST(QuadReadAcrossDiagonal, int32_t); HLK_TEST(QuadReadLaneAt, int64_t); + HLK_TEST(QuadReadAcrossX, int64_t); + HLK_TEST(QuadReadAcrossY, int64_t); + HLK_TEST(QuadReadAcrossDiagonal, int64_t); HLK_TEST(QuadReadLaneAt, uint16_t); + HLK_TEST(QuadReadAcrossX, uint16_t); + HLK_TEST(QuadReadAcrossY, uint16_t); + HLK_TEST(QuadReadAcrossDiagonal, uint16_t); HLK_TEST(QuadReadLaneAt, uint32_t); + HLK_TEST(QuadReadAcrossX, uint32_t); + HLK_TEST(QuadReadAcrossY, uint32_t); + HLK_TEST(QuadReadAcrossDiagonal, uint32_t); HLK_TEST(QuadReadLaneAt, uint64_t); - HLK_TEST(QuadReadLaneAt, float); + HLK_TEST(QuadReadAcrossX, uint64_t); + HLK_TEST(QuadReadAcrossY, uint64_t); + HLK_TEST(QuadReadAcrossDiagonal, uint64_t); HLK_TEST(QuadReadLaneAt, HLSLHalf_t); + HLK_TEST(QuadReadAcrossX, HLSLHalf_t); + HLK_TEST(QuadReadAcrossY, HLSLHalf_t); + HLK_TEST(QuadReadAcrossDiagonal, HLSLHalf_t); + HLK_TEST(QuadReadLaneAt, float); + HLK_TEST(QuadReadAcrossX, float); + HLK_TEST(QuadReadAcrossY, float); + HLK_TEST(QuadReadAcrossDiagonal, float); + HLK_TEST(QuadReadLaneAt, double); + HLK_TEST(QuadReadAcrossX, double); + HLK_TEST(QuadReadAcrossY, double); + HLK_TEST(QuadReadAcrossDiagonal, double); // Wave diff --git a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml index 12b1b04bae..660552b5b2 100644 --- a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml +++ b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml @@ -4295,6 +4295,74 @@ void MSMain(uint GID : SV_GroupIndex, } #endif + #ifdef FUNC_TEST_QUAD_READ_ACROSS_X + void TestQuadReadAcrossX(vector Vector) + { + const uint LaneIndex = WaveGetLaneIndex(); + + // Arbitrarily fill the vector with something different on lane 0. + [unroll] + for(uint i = 0; i < NUM; ++i) + { + Vector[i] = (LaneIndex == 2) ? Vector[2] : Vector[i]; + } + + vector Result = QuadReadAcrossX(Vector); + + // Lane 3 is x=1, so expect that it read the + if(LaneIndex == 3) + { + g_OutputVector.Store< vector >(0, Result); + } + } + #endif + + #ifdef FUNC_TEST_QUAD_READ_ACROSS_Y + void TestQuadReadAcrossY(vector Vector) + { + const uint LaneIndex = WaveGetLaneIndex(); + + // Arbitrarily fill the vector with something different on lane 0. + [unroll] + for(uint i = 0; i < NUM; ++i) + { + Vector[i] = (LaneIndex == 1) ? Vector[2] : Vector[i]; + } + + vector Result = QuadReadAcrossY(Vector); + + // Lane 3 is x=1 and y=1, so expect that we can expect the values to + // match what was on lane 1 for both ReadAcrossY and ReadAcrossX. + if(LaneIndex ==3) + { + g_OutputVector.Store< vector >(0, Result); + } + } + #endif + + #ifdef FUNC_TEST_QUAD_READ_ACROSS_DIAGONAL + void TestQuadReadAcrossDiagonal(vector Vector) + { + const uint LaneIndex = WaveGetLaneIndex(); + + // Arbitrarily fill the vector with something different on lane 0. + [unroll] + for(uint i = 0; i < NUM; ++i) + { + Vector[i] = (LaneIndex == 0) ? Vector[2] : Vector[i]; + } + + vector Result = QuadReadAcrossDiagonal(Vector); + + // Lane 3 is x=1 and y=1, so expect that we can expect the values to + // match what was on lane 1 for both ReadAcrossY and ReadAcrossX. + if(LaneIndex ==3) + { + g_OutputVector.Store< vector >(0, Result); + } + } + #endif + #ifdef NUMTHREADS_XYZ #define NUMTHREADS_ATTR [numthreads(NUMTHREADS_XYZ)] #else From de872d8724284df316c70c78b93e74175aa9f33e Mon Sep 17 00:00:00 2001 From: Alex Sepkowski <5620315+alsepkow@users.noreply.github.com> Date: Thu, 20 Nov 2025 16:10:40 -0800 Subject: [PATCH 05/10] Some cleanup --- .../unittests/HLSLExec/LongVectorOps.def | 30 +++--- .../clang/unittests/HLSLExec/LongVectors.cpp | 94 +++++-------------- .../unittests/HLSLExec/ShaderOpArith.xml | 74 ++++----------- 3 files changed, 60 insertions(+), 138 deletions(-) diff --git a/tools/clang/unittests/HLSLExec/LongVectorOps.def b/tools/clang/unittests/HLSLExec/LongVectorOps.def index 0b23ec4a10..8476fa168b 100644 --- a/tools/clang/unittests/HLSLExec/LongVectorOps.def +++ b/tools/clang/unittests/HLSLExec/LongVectorOps.def @@ -208,13 +208,11 @@ OP_DEFAULT_DEFINES(Wave, WaveReadLaneFirst, 1, "TestWaveReadLaneFirst", "", " -D OP_DEFAULT_DEFINES(Wave, WavePrefixSum, 1, "TestWavePrefixSum", "", " -DFUNC_WAVE_PREFIX_SUM=1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1") OP_DEFAULT_DEFINES(Wave, WavePrefixProduct, 1, "TestWavePrefixProduct", "", " -DFUNC_WAVE_PREFIX_PRODUCT=1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1") -// NOTE: Default2 is used as the input set because Default1 can have precision -// issues with half types in derivative calculations. #define OP_DERIVATIVE(GROUP, SYMBOL, DERIVATIVE_INTRINSIC) \ OP(GROUP, SYMBOL, 1, "TestDerivative", "", "-DFUNC_TEST_DERIVATIVE=1 \ - -DNUMTHREADS_XYZ=2,2,1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1 \ - -DDERIVATIVE_FUNC=" DERIVATIVE_INTRINSIC, "LongVectorOp", Default2, \ - Default1, Default3) + -DNUMTHREADS_XYZ=2,2,1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1" \ + " -DDERIVATIVE_FUNC=" DERIVATIVE_INTRINSIC, \ + "LongVectorOp", Default2, Default1, Default3) OP_DERIVATIVE(Derivative, DerivativeDdx, "ddx") OP_DERIVATIVE(Derivative, DerivativeDdy, "ddy") @@ -223,12 +221,18 @@ OP_DERIVATIVE(Derivative, DerivativeDdyFine, "ddy_fine") #undef OP_DERIVATIVE -OP_DEFAULT_DEFINES(Quad, QuadReadLaneAt, 1, "TestQuadReadLaneAt", "", - " -DFUNC_TEST_QUAD_READ_LANE_AT=1 -DNUMTHREADS_XYZ=2,2,1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1") -OP_DEFAULT_DEFINES(Quad, QuadReadAcrossX, 1, "TestQuadReadAcrossX", "", - " -DFUNC_TEST_QUAD_READ_ACROSS_X=1 -DNUMTHREADS_XYZ=2,2,1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1") -OP_DEFAULT_DEFINES(Quad, QuadReadAcrossY, 1, "TestQuadReadAcrossY", "", - " -DFUNC_TEST_QUAD_READ_ACROSS_Y=1 -DNUMTHREADS_XYZ=2,2,1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1") -OP_DEFAULT_DEFINES(Quad, QuadReadAcrossDiagonal, 1, "TestQuadReadAcrossDiagonal", "", - " -DFUNC_TEST_QUAD_READ_ACROSS_DIAGONAL=1 -DNUMTHREADS_XYZ=2,2,1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1") +#define OP_QUAD_READ(GROUP, ARITY, SYMBOL, QUAD_INTRINSIC, LANE_TO_MODIFY) \ + OP(GROUP, SYMBOL, ARITY, "TestQuadRead", "", "-DFUNC_TEST_QUAD_READ=1" \ + " -DNUMTHREADS_XYZ=2,2,1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1" \ + " -DQUAD_READ_FUNC=" QUAD_INTRINSIC \ + " -DLANE_TO_MODIFY=" LANE_TO_MODIFY, \ + "LongVectorOp", Default1, Default2, Default3) + +OP_QUAD_READ(Quad, 2, QuadReadLaneAt, "QuadReadLaneAt", "2") +OP_QUAD_READ(Quad, 1, QuadReadAcrossX, "QuadReadAcrossX", "2") +OP_QUAD_READ(Quad, 1, QuadReadAcrossY, "QuadReadAcrossY", "1") +OP_QUAD_READ(Quad, 1, QuadReadAcrossDiagonal, "QuadReadAcrossDiagonal", "0") + +#undef OP_QUAD_READ + #undef OP diff --git a/tools/clang/unittests/HLSLExec/LongVectors.cpp b/tools/clang/unittests/HLSLExec/LongVectors.cpp index df04ab5343..2e3a19d7e0 100644 --- a/tools/clang/unittests/HLSLExec/LongVectors.cpp +++ b/tools/clang/unittests/HLSLExec/LongVectors.cpp @@ -1312,78 +1312,34 @@ DEFAULT_OP_1(OpType::DerivativeDdxFine, ((A + 2) - (A + 0))); // Lower left (lane 2) - Top Left (lane 0) DEFAULT_OP_1(OpType::DerivativeDdyFine, ((A + 4) - (A + 0))); -template -struct Op : DefaultValidation {}; - -template struct ExpectedBuilder { - static std::vector buildExpected(Op &, - const InputSets &Inputs) { - DXASSERT_NOMSG(Inputs.size() == 1); - - std::vector Expected; - const size_t VectorSize = Inputs[0].size(); - // As a simple test, we arbitrarily pick the 3rd element to fill the vector - // on a single lane. And then read from it on another lane. - Expected.assign(VectorSize, Inputs[0][2]); - - return Expected; - } -}; - -template -struct Op : DefaultValidation {}; - -template struct ExpectedBuilder { - static std::vector buildExpected(Op &, - const InputSets &Inputs) { - DXASSERT_NOMSG(Inputs.size() == 1); - - std::vector Expected; - const size_t VectorSize = Inputs[0].size(); - // As a simple test, we arbitrarily pick the 3rd element to fill the vector - // on another lane in this quad in the X direction. - Expected.assign(VectorSize, Inputs[0][2]); - - return Expected; - } -}; - -template -struct Op : DefaultValidation {}; - -template struct ExpectedBuilder { - static std::vector buildExpected(Op &, - const InputSets &Inputs) { - DXASSERT_NOMSG(Inputs.size() == 1); - - std::vector Expected; - const size_t VectorSize = Inputs[0].size(); - // As a simple test, we arbitrarily pick the 3rd element to fill the vector - // on another lane in this quad in the Y direction. - Expected.assign(VectorSize, Inputs[0][2]); - - return Expected; - } -}; - -template -struct Op : DefaultValidation {}; - -template struct ExpectedBuilder { - static std::vector buildExpected(Op &, - const InputSets &Inputs) { - DXASSERT_NOMSG(Inputs.size() == 1); +// +// Quad Read Ops +// - std::vector Expected; - const size_t VectorSize = Inputs[0].size(); - // As a simple test, we arbitrarily pick the 3rd element to fill the vector - // on another lane in this quad in the Y direction. - Expected.assign(VectorSize, Inputs[0][2]); +// We keep things generic so we can re-use this macro for all quad ops. +// The lane we write to is determined via a defines in the shader code via a +// defines. See TestQuadRead in ShaderOpArith.xml. +// For all cases we simply fill the vector on that lane with the value of the +// third element. +#define QUAD_READ_OP(OP, ARITY) \ + template struct Op : DefaultValidation {}; \ + template struct ExpectedBuilder { \ + static std::vector buildExpected(Op &, \ + const InputSets &Inputs) { \ + DXASSERT_NOMSG(Inputs.size() == ARITY); \ + std::vector Expected; \ + const size_t VectorSize = Inputs[0].size(); \ + Expected.assign(VectorSize, Inputs[0][2]); \ + return Expected; \ + } \ + }; - return Expected; - } -}; +QUAD_READ_OP(OpType::QuadReadLaneAt, 2); +QUAD_READ_OP(OpType::QuadReadAcrossX, 1); +QUAD_READ_OP(OpType::QuadReadAcrossY, 1); +QUAD_READ_OP(OpType::QuadReadAcrossDiagonal, 1); +#undef QUAD_READ_OP // // Wave Ops diff --git a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml index 660552b5b2..7d4d86d27d 100644 --- a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml +++ b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml @@ -4274,19 +4274,27 @@ void MSMain(uint GID : SV_GroupIndex, } #endif - #ifdef FUNC_TEST_QUAD_READ_LANE_AT - void TestQuadReadLaneAt(vector Vector) + #ifdef FUNC_TEST_QUAD_READ + void TestQuadRead(vector Vector) { const uint LaneIndex = WaveGetLaneIndex(); - // Arbitrarily fill the vector with something different on lane 2. + // Fill the long vector with something different on LANE_TO_MODIFY. + // We choose the 3rd element arbitrarily because it makes it easy + // to compute expected values CPU side. [unroll] for(uint i = 0; i < NUM; ++i) { - Vector[i] = (LaneIndex == 2) ? Vector[2] : Vector[i]; + Vector[i] = (LaneIndex == LANE_TO_MODIFY) ? Vector[2] : Vector[i]; } - vector Result = QuadReadLaneAt(Vector, 2); + #if IS_BINARY_OP + // QuadReadLaneAt + vector Result = QUAD_READ_FUNC(Vector, LANE_TO_MODIFY); + #else + // QuadReadAcross* + vector Result = QUAD_READ_FUNC(Vector); + #endif if(LaneIndex == 3) { @@ -4295,21 +4303,21 @@ void MSMain(uint GID : SV_GroupIndex, } #endif - #ifdef FUNC_TEST_QUAD_READ_ACROSS_X - void TestQuadReadAcrossX(vector Vector) + #ifdef FUNC_TEST_QUAD_READ_LANE_AT + void TestQuadReadLaneAt(vector Vector) { const uint LaneIndex = WaveGetLaneIndex(); - // Arbitrarily fill the vector with something different on lane 0. + // Arbitrarily fill the vector with something different on lane 2. [unroll] for(uint i = 0; i < NUM; ++i) { Vector[i] = (LaneIndex == 2) ? Vector[2] : Vector[i]; } - vector Result = QuadReadAcrossX(Vector); + + vector Result = QUAD_READ_FUNC(Vector, 2); - // Lane 3 is x=1, so expect that it read the if(LaneIndex == 3) { g_OutputVector.Store< vector >(0, Result); @@ -4317,52 +4325,6 @@ void MSMain(uint GID : SV_GroupIndex, } #endif - #ifdef FUNC_TEST_QUAD_READ_ACROSS_Y - void TestQuadReadAcrossY(vector Vector) - { - const uint LaneIndex = WaveGetLaneIndex(); - - // Arbitrarily fill the vector with something different on lane 0. - [unroll] - for(uint i = 0; i < NUM; ++i) - { - Vector[i] = (LaneIndex == 1) ? Vector[2] : Vector[i]; - } - - vector Result = QuadReadAcrossY(Vector); - - // Lane 3 is x=1 and y=1, so expect that we can expect the values to - // match what was on lane 1 for both ReadAcrossY and ReadAcrossX. - if(LaneIndex ==3) - { - g_OutputVector.Store< vector >(0, Result); - } - } - #endif - - #ifdef FUNC_TEST_QUAD_READ_ACROSS_DIAGONAL - void TestQuadReadAcrossDiagonal(vector Vector) - { - const uint LaneIndex = WaveGetLaneIndex(); - - // Arbitrarily fill the vector with something different on lane 0. - [unroll] - for(uint i = 0; i < NUM; ++i) - { - Vector[i] = (LaneIndex == 0) ? Vector[2] : Vector[i]; - } - - vector Result = QuadReadAcrossDiagonal(Vector); - - // Lane 3 is x=1 and y=1, so expect that we can expect the values to - // match what was on lane 1 for both ReadAcrossY and ReadAcrossX. - if(LaneIndex ==3) - { - g_OutputVector.Store< vector >(0, Result); - } - } - #endif - #ifdef NUMTHREADS_XYZ #define NUMTHREADS_ATTR [numthreads(NUMTHREADS_XYZ)] #else From 8726fe37400ce0f6ddda4f473b2ec163f97cb1d5 Mon Sep 17 00:00:00 2001 From: Alex Sepkowski <5620315+alsepkow@users.noreply.github.com> Date: Thu, 20 Nov 2025 16:16:23 -0800 Subject: [PATCH 06/10] Clean up comments --- tools/clang/unittests/HLSLExec/LongVectors.cpp | 4 ++-- tools/clang/unittests/HLSLExec/ShaderOpArith.xml | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tools/clang/unittests/HLSLExec/LongVectors.cpp b/tools/clang/unittests/HLSLExec/LongVectors.cpp index 2e3a19d7e0..6366f01778 100644 --- a/tools/clang/unittests/HLSLExec/LongVectors.cpp +++ b/tools/clang/unittests/HLSLExec/LongVectors.cpp @@ -1300,8 +1300,8 @@ template struct ExpectedBuilder { // Derivative Ops // -// Coarse derivative ops return the same partial derivative value for all lanes -// in the quad. +// ddx and ddy are the same thing as the coarse versions. That is, they +// return the same partial derivative value in all lanes for the quad. // Top right (lane 1) - Top Left (lane 0) DEFAULT_OP_1(OpType::DerivativeDdx, ((A + 2) - (A + 0))); // Lower left (lane 2) - Top Left (lane 0) diff --git a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml index 7d4d86d27d..72e2e25217 100644 --- a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml +++ b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml @@ -4257,15 +4257,18 @@ void MSMain(uint GID : SV_GroupIndex, const uint LaneIndex = WaveGetLaneIndex(); - // Need to make the values unique across lanes so we can get a - // non-zero partial derivative. + // We need to make the values are unique across lanes used in the + // partial derivative calculation so we can get a non-zero partial + // derivative. Multiplying the lane index by 2 is a simple way to + // ensure that. And we do this on all lanes so this function can be + // used generically for coarse and fine partial derivatives. Vector += ((TYPE)(LaneIndex * 2)); vector Result = DERIVATIVE_FUNC(Vector); // For coarse derivatives, all lanes in the quad get the same result. // But for fine derivatives, each lane gets a different result. To - // keep things simple we only store in the third lane as thats the + // keep things generic we only store in the third lane as thats the // lane we arbitrarily chose for validation with fine derivatives. if(LaneIndex == 3) { From ba59d903e7eebf0a372219282cd1fafff79773f5 Mon Sep 17 00:00:00 2001 From: Alex Sepkowski <5620315+alsepkow@users.noreply.github.com> Date: Thu, 20 Nov 2025 16:31:50 -0800 Subject: [PATCH 07/10] Cleanup ShaderOpArith.xml --- .../unittests/HLSLExec/ShaderOpArith.xml | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml index 72e2e25217..eef5144e88 100644 --- a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml +++ b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml @@ -4306,28 +4306,6 @@ void MSMain(uint GID : SV_GroupIndex, } #endif - #ifdef FUNC_TEST_QUAD_READ_LANE_AT - void TestQuadReadLaneAt(vector Vector) - { - const uint LaneIndex = WaveGetLaneIndex(); - - // Arbitrarily fill the vector with something different on lane 2. - [unroll] - for(uint i = 0; i < NUM; ++i) - { - Vector[i] = (LaneIndex == 2) ? Vector[2] : Vector[i]; - } - - - vector Result = QUAD_READ_FUNC(Vector, 2); - - if(LaneIndex == 3) - { - g_OutputVector.Store< vector >(0, Result); - } - } - #endif - #ifdef NUMTHREADS_XYZ #define NUMTHREADS_ATTR [numthreads(NUMTHREADS_XYZ)] #else From 5d020f172efa0ee54a45bf1ad2336905574ba521 Mon Sep 17 00:00:00 2001 From: Alex Sepkowski <5620315+alsepkow@users.noreply.github.com> Date: Thu, 20 Nov 2025 16:45:42 -0800 Subject: [PATCH 08/10] Self PR review --- tools/clang/unittests/HLSLExec/LongVectorOps.def | 4 ++-- tools/clang/unittests/HLSLExec/LongVectors.cpp | 16 ++++++++++------ tools/clang/unittests/HLSLExec/ShaderOpArith.xml | 6 +++--- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/tools/clang/unittests/HLSLExec/LongVectorOps.def b/tools/clang/unittests/HLSLExec/LongVectorOps.def index 8476fa168b..88256e7cef 100644 --- a/tools/clang/unittests/HLSLExec/LongVectorOps.def +++ b/tools/clang/unittests/HLSLExec/LongVectorOps.def @@ -221,11 +221,11 @@ OP_DERIVATIVE(Derivative, DerivativeDdyFine, "ddy_fine") #undef OP_DERIVATIVE -#define OP_QUAD_READ(GROUP, ARITY, SYMBOL, QUAD_INTRINSIC, LANE_TO_MODIFY) \ +#define OP_QUAD_READ(GROUP, ARITY, SYMBOL, QUAD_INTRINSIC, SOURCE_LANE_ID) \ OP(GROUP, SYMBOL, ARITY, "TestQuadRead", "", "-DFUNC_TEST_QUAD_READ=1" \ " -DNUMTHREADS_XYZ=2,2,1 -DOP_STORES_RESULT_ON_SPECIFIC_LANE=1" \ " -DQUAD_READ_FUNC=" QUAD_INTRINSIC \ - " -DLANE_TO_MODIFY=" LANE_TO_MODIFY, \ + " -DSOURCE_LANE_ID=" SOURCE_LANE_ID, \ "LongVectorOp", Default1, Default2, Default3) OP_QUAD_READ(Quad, 2, QuadReadLaneAt, "QuadReadLaneAt", "2") diff --git a/tools/clang/unittests/HLSLExec/LongVectors.cpp b/tools/clang/unittests/HLSLExec/LongVectors.cpp index 6366f01778..29c5cb31c8 100644 --- a/tools/clang/unittests/HLSLExec/LongVectors.cpp +++ b/tools/clang/unittests/HLSLExec/LongVectors.cpp @@ -1300,17 +1300,21 @@ template struct ExpectedBuilder { // Derivative Ops // -// ddx and ddy are the same thing as the coarse versions. That is, they -// return the same partial derivative value in all lanes for the quad. +// Coarse derivatives (ddx/ddy): All lanes in quad get same result +// Fine derivatives (ddx_fine/ddy_fine): Each lane gets unique result +// For testing, we validate results on lane 3 to keep validation generic +// +// The value of A in each lane is computed by : A = A + LaneID*2 +// // Top right (lane 1) - Top Left (lane 0) DEFAULT_OP_1(OpType::DerivativeDdx, ((A + 2) - (A + 0))); // Lower left (lane 2) - Top Left (lane 0) DEFAULT_OP_1(OpType::DerivativeDdy, ((A + 4) - (A + 0))); -// Fine derivative ops return different partial derivative values for each -DEFAULT_OP_1(OpType::DerivativeDdxFine, ((A + 2) - (A + 0))); -// Lower left (lane 2) - Top Left (lane 0) -DEFAULT_OP_1(OpType::DerivativeDdyFine, ((A + 4) - (A + 0))); +// Bottom right (lane 3) - Bottom left (lane 2) +DEFAULT_OP_1(OpType::DerivativeDdxFine, ((A + 6) - (A + 4))); +// Bottom right (lane 3) - Top right (lane 1) +DEFAULT_OP_1(OpType::DerivativeDdyFine, ((A + 6) - (A + 2))); // // Quad Read Ops diff --git a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml index eef5144e88..b4e72569c2 100644 --- a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml +++ b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml @@ -4282,18 +4282,18 @@ void MSMain(uint GID : SV_GroupIndex, { const uint LaneIndex = WaveGetLaneIndex(); - // Fill the long vector with something different on LANE_TO_MODIFY. + // Fill the long vector with something different on SOURCE_LANE_ID. // We choose the 3rd element arbitrarily because it makes it easy // to compute expected values CPU side. [unroll] for(uint i = 0; i < NUM; ++i) { - Vector[i] = (LaneIndex == LANE_TO_MODIFY) ? Vector[2] : Vector[i]; + Vector[i] = (LaneIndex == SOURCE_LANE_ID) ? Vector[2] : Vector[i]; } #if IS_BINARY_OP // QuadReadLaneAt - vector Result = QUAD_READ_FUNC(Vector, LANE_TO_MODIFY); + vector Result = QUAD_READ_FUNC(Vector, SOURCE_LANE_ID); #else // QuadReadAcross* vector Result = QUAD_READ_FUNC(Vector); From fba5bd94e0898143d71f4e672120025734f0b335 Mon Sep 17 00:00:00 2001 From: Alex Sepkowski Date: Thu, 20 Nov 2025 17:09:05 -0800 Subject: [PATCH 09/10] Update tools/clang/unittests/HLSLExec/LongVectors.cpp Co-authored-by: Damyan Pepper --- tools/clang/unittests/HLSLExec/LongVectors.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/clang/unittests/HLSLExec/LongVectors.cpp b/tools/clang/unittests/HLSLExec/LongVectors.cpp index 29c5cb31c8..cd52c75171 100644 --- a/tools/clang/unittests/HLSLExec/LongVectors.cpp +++ b/tools/clang/unittests/HLSLExec/LongVectors.cpp @@ -1321,8 +1321,8 @@ DEFAULT_OP_1(OpType::DerivativeDdyFine, ((A + 6) - (A + 2))); // // We keep things generic so we can re-use this macro for all quad ops. -// The lane we write to is determined via a defines in the shader code via a -// defines. See TestQuadRead in ShaderOpArith.xml. +// The lane we write to is determined via a defines in the shader code. +// See TestQuadRead in ShaderOpArith.xml. // For all cases we simply fill the vector on that lane with the value of the // third element. #define QUAD_READ_OP(OP, ARITY) \ From 9ed37968bb7fab255124ff47ac0ac02ad0beffb2 Mon Sep 17 00:00:00 2001 From: Alex Sepkowski Date: Thu, 20 Nov 2025 17:09:13 -0800 Subject: [PATCH 10/10] Update tools/clang/unittests/HLSLExec/ShaderOpArith.xml Co-authored-by: Damyan Pepper --- tools/clang/unittests/HLSLExec/ShaderOpArith.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml index b4e72569c2..b271cde524 100644 --- a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml +++ b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml @@ -4257,7 +4257,7 @@ void MSMain(uint GID : SV_GroupIndex, const uint LaneIndex = WaveGetLaneIndex(); - // We need to make the values are unique across lanes used in the + // We need to make sure the values are unique across lanes used in the // partial derivative calculation so we can get a non-zero partial // derivative. Multiplying the lane index by 2 is a simple way to // ensure that. And we do this on all lanes so this function can be