[HLSL] Correct LinAlg OuterProduct accumulator use (#8662)
## Summary
`OuterProduct` produces an accumulator, not a matrix-A operand. Proposal
0035 defines `dx::linalg::OuterProduct` as returning `Matrix<...,
MatrixUse::Accumulator, MatrixScope::Thread>`, and DXC's public
`<dx/linalg.h>` API implements that contract. The execution test instead
hard-coded `USE_A`, so its emitted DXIL described the result as a
matrix-A value (`U0`) before passing it to the accumulator-store path.
This change:
- declares the result using the shared `USE` parameter;
- sets the host parameter to `MatrixUse::Accumulator`;
- asserts that invariant in the host runner; and
- changes the emitted matrix metadata from `U0` (`A`) to `U2`
(`Accumulator`) while preserving the existing arithmetic and exact
value-4 result.
## Why this is needed
The original test was out of the SM6.10 proposal and public API
contract.
The mismatch was easy to miss because `MatrixUse` is type metadata
rather than part of the numerical outer-product calculation. The current
DXIL validator checks that an OuterProduct result has well-formed matrix
metadata, dimensions, and component type, but does not enforce that its
use is `Accumulator`. Consequently, the old shader compiled and produced
the expected numbers while exercising the wrong matrix role. Leaving it
unchanged would let the execution/HLK test bless `U0` metadata even
though source compiled through `dx::linalg::OuterProduct` produces `U2`.
This is therefore a conformance correction, not a functional expansion.
It adds no new shapes, types, scopes, or capability handling.
Refs #7841
Refs #8563
Refs #8561
Closes #8682
Assisted-by: GitHub Copilot
Co-authored-by: Jack Elliott <jackell@ntdev.microsoft.com>
Copilot-Session: 83725f5d-8e98-4c1d-91ee-ad47629e007b
diff --git a/tools/clang/unittests/HLSLExec/LinAlgTests.cpp b/tools/clang/unittests/HLSLExec/LinAlgTests.cpp
index 8db0c67..ea3391b 100644
--- a/tools/clang/unittests/HLSLExec/LinAlgTests.cpp
+++ b/tools/clang/unittests/HLSLExec/LinAlgTests.cpp
@@ -1395,7 +1395,6 @@
}
static const char OuterProductShader[] = R"(
- #define USE_A 0
#define SCOPE_THREAD 0
RWByteAddressBuffer Input : register(u0);
@@ -1416,7 +1415,7 @@
}
__builtin_LinAlgMatrix
- [[__LinAlgMatrix_Attributes(COMP_TYPE, M_DIM, N_DIM, USE_A, SCOPE_THREAD)]]
+ [[__LinAlgMatrix_Attributes(COMP_TYPE, M_DIM, N_DIM, USE, SCOPE_THREAD)]]
Mat;
__builtin_LinAlg_MatrixOuterProduct(Mat, VecA, VecB);
@@ -1434,6 +1433,8 @@
VERIFY_IS_TRUE(
Params.Layout == MatrixLayout::OuterProductOptimal,
"Outer product must output its matrix in OuterProductOptimal layout");
+ VERIFY_IS_TRUE(Params.Use == MatrixUse::Accumulator,
+ "Outer product must output an accumulator matrix");
const size_t NumVecElements = Params.M + Params.N;
const size_t InBuffSize = NumVecElements * elementSize(Params.CompType);
const size_t NumMatElements = Params.totalElements();
@@ -1502,6 +1503,7 @@
Params.CompType = ComponentType::F16;
Params.M = 16;
Params.N = 16;
+ Params.Use = MatrixUse::Accumulator;
Params.Scope = MatrixScope::Thread;
Params.Layout = MatrixLayout::OuterProductOptimal;
Params.NumThreads = 1;