Skip to content

[HLSL] Fix LinAlg stride and group-shared offset preconditions - #8865

Merged
Jack Elliott (JoeCitizen) merged 3 commits into
microsoft:mainfrom
JoeCitizen:linalg-hlk-stride-preconditions
Sep 1, 2026
Merged

[HLSL] Fix LinAlg stride and group-shared offset preconditions#8865
Jack Elliott (JoeCitizen) merged 3 commits into
microsoft:mainfrom
JoeCitizen:linalg-hlk-stride-preconditions

Conversation

@JoeCitizen

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

Copy link
Copy Markdown
Collaborator

Proposal 0035 requires linear algebra matrix memory strides to be a multiple of 16 bytes and group-shared matrix starts to be 128-byte aligned, but ten cases were passing illegal operands and only passing because WARP is more permissive than the specification requires.

Assisted-by: GitHub Copilot

Jack Elliott and others added 2 commits September 1, 2026 10:04
Proposal 0035 requires that the Stride argument of a matrix Load on a
[RW]ByteAddressBuffer be a multiple of 16 bytes. matrixStrideBytes returned
the tightly packed stride, so three positive tests were driving the shader
with an 8-byte descriptor stride:

  MatVecMul_Thread_4x8_F16_ColumnMajor   4 * 2 bytes = 8
  MatVecMul_Thread_4x8_I8_Interpreted    8 * 1 bytes = 8
  MatVecMul_Thread_4x8_U8_Interpreted    8 * 1 bytes = 8

These pass today, but the proposal does not define runtime behaviour once
the precondition is violated, so a pass cannot be used as conformance
evidence and a stricter implementation could fail them at any time.

Round the stride up to a multiple of 16 in matrixStrideBytes, which is the
single value feeding the host buffer encoding, the buffer size and the
-DMATRIX_STRIDE shader argument, so all three stay consistent by
construction. Padding only inserts zero gaps between rows or columns;
calculateExpected indexes the logical matrix values and never consults the
stride, so no oracle changes. The other three MatVec cases are already
16-byte aligned and are unaffected: U32 4x8 RowMajor is 32, FP8 4x16 is 16,
and F16 4x8 RowMajor is 16.

Also add the stride postcondition to isCaseValid, which was deliberately
left out while the I8 and U8 cases still used a stride of 8.

Negative controls, both predicted before running. Removing the padding while
keeping the postcondition failed exactly the three cases above and nothing
else, confirming they were the only violators. Keeping the padded shader
stride while encoding the host buffer at the packed stride also failed
exactly those three, confirming the padded stride reaches the shader and the
buffer is really laid out at the new stride.

Per-test differential against 8320476 with no outcome changes in either
configuration: released SDK 78/73/0/5, preview SDK 78/74/2/2. The two
preview failures are the pre-existing toLinAlgDataType FP8 gap, unrelated
to this change.

Assisted-by: GitHub Copilot
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 83725f5d-8e98-4c1d-91ee-ad47629e007b
Proposal 0035 requires a matrix stride in memory to be a multiple of 16
bytes, and requires the start of a group-shared matrix to be 128-byte
aligned. Seven more positive tests were driving out-of-contract layouts:

  CopyConvert_Wave_4x8_F32_ToF16_Transpose   destination stride 8
  LoadStoreMemory_Wave_4x8_F16_RowMajorOffsetPadded    offset 8, stride 24
                                             and canonical stride 8
  LoadStoreMemory_Wave_4x8_F32_ColumnMajorOffsetPadded offset 16, stride 24
  LoadStoreMemory_ThreadGroup_4x8_F16                  offset 8, stride 12
  AccumulateMemory_Wave_16x16_F16 padded subcase       offset 8, stride 24
  AccumulateMemoryContention_Wave_4x8_F16              offset 8, stride 24
  AccumulateMemoryContention_Wave_4x8_I32              offset 16, stride 40

Round MatrixParams::strideBytes up to a multiple of 16, which covers the
CopyConvert destination and every other descriptor stride derived from it,
and keeps returning 0 for the optimal layouts where the proposal requires
it. Move the alignment constants next to it so the MatVec helper, the
group-shared gate and the existing DescriptorAlignedOffset all share one
definition instead of repeating the literals.

Re-pad the group-shared layouts so each one still exercises a padded stride
and a non-zero start while satisfying the preconditions, and enforce both
rules in getGroupSharedBufferDescription, which every group-shared Load,
Store and Accumulate path already funnels through. That turns a silent
out-of-contract layout into an immediate failure and stops this class of
violation being reintroduced.

The oracles follow the layout rather than the other way around: buffer
sizes, the host encoding and the shader offset and stride arguments are all
derived from the same MatrixBufferLayout, so re-padding needs no separate
expectation update.

The unaligned layouts remaining in LinAlgCPUOracleTests are deliberate.
Those are host-only tests of writeMatrixBuffer and verifyMatrixBuffer
padding behaviour, they run no shader, and the DXIL preconditions do not
apply to them.

Negative controls, both predicted before running. Reverting the ThreadGroup
target offset to 8 failed exactly that test with "Invalid group-shared
buffer description", confirming the new gate is live. Keeping the padded
DST_STRIDE while encoding the host destination at the packed stride failed
exactly CopyConvert_Wave_4x8_F32_ToF16_Transpose, confirming the padded
stride reaches the shader.

Per-test differential against 8320476 with no outcome changes in either
configuration: released SDK 78/73/0/5, preview SDK 78/74/2/2. abicheck
EXITCODE=0.

AccumulateMemoryContention_Wave_4x8_I32 is capability-skipped on the test
device, so its new layout is compiled but not executed here.

Assisted-by: GitHub Copilot
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 83725f5d-8e98-4c1d-91ee-ad47629e007b
@JoeCitizen
Jack Elliott (JoeCitizen) marked this pull request as ready for review August 31, 2026 23:03
Copilot AI balanced review requested due to automatic review settings August 31, 2026 23:03

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

Updates linear algebra execution tests to comply with Proposal 0035 alignment requirements.

Changes:

  • Aligns matrix strides to 16 bytes.
  • Aligns group-shared matrix offsets to 128 bytes.
  • Rejects invalid group-shared layouts.

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

Comment thread tools/clang/unittests/HLSLExec/LinAlgTests.cpp Outdated

@alsepkow Alex Sepkowski (alsepkow) 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.

LGTM with one minor comment.

The previous commit introduced MatrixStrideAlignmentBytes,
MatrixOffsetAlignmentBytes and alignMatrixStride(), but only
runGroupSharedAccumulateContention actually used them. The four other
group-shared layouts it updated kept hand-computed literals, so the file
carried both the rule and a set of numbers that happened to satisfy it,
with nothing tying the two together.

Each padded offset is now MatrixOffsetAlignmentBytes, and each stride is
derived from the matrix that uses it: alignMatrixStride() of the minor
extent times the component size for a tight-but-aligned stride, plus one
or two MatrixStrideAlignmentBytes units where the case deliberately pads.
That makes the intent readable at the use site - a reader can now see
which layouts are packed and which are padded without recomputing element
sizes - and it keeps the strides legal if a case ever changes shape or
component type.

Zero offsets are left as literals. Proposal 0035 constrains the alignment
of a non-zero matrix start, so a zero there means "no offset" rather than
an alignment choice, and naming it after the alignment constant would
misdescribe it.

Two nearby groups of literals are deliberately unchanged. The descriptor
layouts already route their offsets through DescriptorAlignedOffset and
carry comments deriving their strides, and they are not touched by this
change. The LinAlgCPUOracleTests layouts use offsets and strides such as
4 and 12 precisely because they are not legal GPU matrix strides; they
exercise the host codec's arithmetic, and forcing them onto 16- and
128-byte boundaries would delete that coverage.

No value changes. Every substitution was checked against the literal it
replaced by static_assert in a standalone translation unit, and that
check was verified non-vacuous by injecting two wrong expectations and
confirming both failed to compile. On preview WARP the suite is
Total=78, Passed=74, Failed=2, Skipped=2, with zero per-test differences
against the parent commit across all 78 methods. The two failures are
the FP8 conversion cases, which need the type mapping in microsoft#8866 and are
unrelated to this change.

Addresses review feedback from @alsepkow.

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

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.

@llvm-beanz

Copy link
Copy Markdown
Collaborator

FYI: there is a related spec change coming around this in response to microsoft/hlsl-specs#922.

@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.

Ashley Coleman (@V-FEXrt) - should we have expected the validator catch this at this point, or is validation for this not in main yet?

@JoeCitizen
Jack Elliott (JoeCitizen) merged commit 4c7c497 into microsoft:main Sep 1, 2026
13 checks passed
@github-project-automation github-project-automation Bot moved this from New to Done in HLSL Roadmap Sep 1, 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.

5 participants