Skip to content

[HLSL] Add out-of-bounds store coverage for LinAlg descriptor stores - #8769

Merged
Jack Elliott (JoeCitizen) merged 3 commits into
microsoft:mainfrom
JoeCitizen:linalg-hlk-descriptor-store-oob
Aug 13, 2026
Merged

[HLSL] Add out-of-bounds store coverage for LinAlg descriptor stores#8769
Jack Elliott (JoeCitizen) merged 3 commits into
microsoft:mainfrom
JoeCitizen:linalg-hlk-descriptor-store-oob

Conversation

@JoeCitizen

@JoeCitizen Jack Elliott (JoeCitizen) commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Proposal 0035 requires MatrixStoreToDescriptor to bounds check its writes, permitting either dropping the whole store if any element falls outside the descriptor view, or dropping only the elements that fall outside.

These two tests store through a destination view shorter than its buffer, mirroring the existing load cases.

Proposal 0035 requires MatrixStoreToDescriptor to bounds check its
writes, permitting either of two behaviours: drop the whole store if any
element falls outside the descriptor view, or drop only the elements
that fall outside. The suite already covers the load side of that rule.
Nothing covered the store side, so an implementation that wrote past its
descriptor view passed.

Adds two tests that store a matrix through a destination view shorter
than its buffer, mirroring the two existing load cases. One uses a
packed 16x16 F16 matrix with a 260 byte view, admitting 130 of 256
elements. The other uses a 4x8 F16 matrix at a 128 byte offset with a
172 byte view, admitting 14 of 32. Both boundaries fall inside a row
rather than on a row or padding edge.

The comparison is byte level rather than matrix level. Both permitted
behaviours leave the bytes past the view unwritten, holding the poison
the destination was seeded with, so there is no element value to compare
against; decoding those bytes as F16 can also produce NaN, which does
not compare equal to itself. Two host helpers support this:
storeBufferBoundedByView derives the expected bytes for a given view,
and verifyStoreBuffer reports the first differing byte for each
candidate.

The source is viewed in full so only the destination is bounds checked,
leaving the result attributable to the store alone. The runner also
asserts that the chosen view both admits and excludes at least one whole
element, since a view that did neither would accept any result.

These cases cannot by themselves fail an implementation that stores
nothing at all, because dropping the whole store is one of the two
permitted behaviours. The existing LoadStoreDescriptor cases, which view
the destination in full, are what require the store to happen.

The 260 byte boundary is deliberate. An earlier draft used 264, which
admits 132 elements. That is exactly 33 times 4, so on a device with a
64 lane wave and four elements per lane, an implementation that bounds
checked once per lane rather than once per element would see every lane
as wholly inside or wholly outside and produce output identical to
per-element checking. Per-lane checking is not one of the two permitted
behaviours, so that would have been a false pass. 130 is not a multiple
of the per-lane element count at any wave size the tile supports below
128 lanes.

Validated on WARP: 36 total, 31 passed, 4 failed, 1 skipped, with the
non-passing set identical to the branch baseline of 33/28/4/1. Two
controls confirm the tests detect what they claim. Widening the
destination view to the full buffer fails both, reporting the first
differing byte at 260, exactly the view boundary. Making the host oracle
write zeroes instead of restoring poison fails the oracle self-test,
which the previous value-only check would have passed silently.

Assisted-by: GitHub Copilot
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 83725f5d-8e98-4c1d-91ee-ad47629e007b
Copilot AI balanced review requested due to automatic review settings August 12, 2026 18:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds conformance coverage for Proposal 0035’s out-of-bounds descriptor store behavior.

Changes:

  • Adds byte-level store-result oracles with poison preservation.
  • Tests packed and offset/padded partial destination views.
  • Adds CPU coverage for view-boundary handling.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@damyanp Damyan Pepper (damyanp) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, would be good to get more domain expertise looking at it.

Comment thread tools/clang/unittests/HLSLExec/LinAlgTests.cpp Outdated
Co-authored-by: Alex Sepkowski <alexsepkowski@gmail.com>
Copilot AI review requested due to automatic review settings August 13, 2026 01:40
@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff bc0a474927ed1d8018854ead41a33616aed4a4c6 c9f2f5ea189174eaf1cd1bd13fa02ca6cdaaadc9 -- tools/clang/unittests/HLSLExec/LinAlgTests.cpp
View the diff from clang-format here.
diff --git a/tools/clang/unittests/HLSLExec/LinAlgTests.cpp b/tools/clang/unittests/HLSLExec/LinAlgTests.cpp
index c6750a62..c077552a 100644
--- a/tools/clang/unittests/HLSLExec/LinAlgTests.cpp
+++ b/tools/clang/unittests/HLSLExec/LinAlgTests.cpp
@@ -1326,8 +1326,8 @@ static bool verifyStoreBuffer(const void *ActualBuffer, size_t ActualBufferSize,
                               const std::wstring &PublicRule, bool Verbose) {
   if (Candidates.size() < 2 || PublicRule.empty()) {
     hlsl_test::LogErrorFmt(
-    L"Invalid store buffer oracle: candidates=%zu, public rule is %s",
-    Candidates.size(), PublicRule.empty() ? L"empty" : L"present");
+        L"Invalid store buffer oracle: candidates=%zu, public rule is %s",
+        Candidates.size(), PublicRule.empty() ? L"empty" : L"present");
     return false;
   }
 
  • Check this box to apply formatting changes to this branch.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Suppressed comments (1)

tools/clang/unittests/HLSLExec/LinAlgTests.cpp:1329

  • This continuation line is misindented relative to the surrounding formatted calls. Reindent the format string so this hunk remains clang-formatted.
    L"Invalid store buffer oracle: candidates=%zu, public rule is %s",

Copilot AI review requested due to automatic review settings August 13, 2026 01:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@JoeCitizen
Jack Elliott (JoeCitizen) enabled auto-merge (squash) August 13, 2026 01:58
@JoeCitizen
Jack Elliott (JoeCitizen) merged commit f78edc6 into microsoft:main Aug 13, 2026
11 checks passed
@github-project-automation github-project-automation Bot moved this from New to Done in HLSL Roadmap Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants