Skip to content

fix(rocjitsu): treat a zero tensor extent as empty, not unbounded - #10333

Closed
amd-arosa wants to merge 1 commit into
developfrom
users/arosa/rocjitsu/fix/tensor-extent
Closed

amd-arosa wants to merge 1 commit into
developfrom
users/arosa/rocjitsu/fix/tensor-extent

Conversation

@amd-arosa

Copy link
Copy Markdown
Contributor

Motivation

At origin/develop, copy_dense_tensor() in emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/isa/arch/amdgpu/shared/tensor_dma.h wrote if (desc.tensor_dims[dim] != 0 && coord >= desc.tensor_dims[dim]) in_bounds = false;, so a zero per-dimension tensor extent disabled the bounds check for that dimension and the tile was treated as unbounded there. For a dense descriptor that is wrong: rank() is derived from tile_dims, and parse_descriptor() populates a real extent field for every dimension below that rank, so zero cannot be an "unset" sentinel — it means the tensor is empty in that dimension and every coordinate is out of bounds. The fix drops the zero guard, evaluating coord >= desc.tensor_dims[dim] unconditionally; out-of-bounds elements then take the path copy_bytes() already had (zero into LDS on a load, nothing written on a store). copy_gather_tensor() is correctly left alone, since a gather descriptor's rank is derived from the extents themselves. The source hunk is substantively identical to the reference fix 24fce1a489, and the new test reproduces the defect exactly.

What a guest program saw before this change: A guest program whose descriptor had counted an extent down to zero — the last prefetch of a pipelined loop, where the base has advanced past the end of the tensor and nothing is left behind it — got a full tile copied from beyond the allocation. A TENSOR_LOAD_TO_LDS pulled whatever followed the tensor in device memory into LDS instead of zeros; a TENSOR_STORE_FROM_LDS wrote the tile over memory the guest never named. On the motivating case (mxfp_fa_cdna5, a 256x8 tile) the out-of-bounds read reportedly took the emulator down with a host SIGSEGV.

Technical Details

Changed files:

  • /tmp/rj-fix-tensor-extent/emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/isa/arch/amdgpu/shared/tensor_dma.h
  • /tmp/rj-fix-tensor-extent/emulation/rocjitsu/tests/cdna5_tensor_dma_test.cpp

Issue Tracking

GitHub issue: #10327

Test Plan

Written test-first: the regression test was added and observed to fail against
develop before any source change, then the fix was applied and the test
re-run. New tests:

  • Gfx1250ExecutionTest.TensorDmaEmptyTensorExtentReadsNothing

Failure observed before the fix:

/tmp/rj-fix-tensor-extent/emulation/rocjitsu/tests/cdna5_tensor_dma_test.cpp:790: Failure
Expected equality of these values:
  cu->lds().read32(wf->lds_base() + i * 4)
    Which is: 1711276032
  0u
    Which is: 0
lds element 0

/tmp/rj-fix-tensor-extent/emulation/rocjitsu/tests/cdna5_tensor_dma_test.cpp:790: Failure
Expected equality of these values:
  cu->lds().read32(wf->lds_base() + i * 4)
    Which is: 1711276033
  0u
    Which is: 0
lds element 1

[...]

/tmp/rj-fix-tensor-extent/emulation/rocjitsu/tests/cdna5_tensor_dma_test.cpp:800: Failure
Expected equality of these values:
  read_global_u32(*sim.memory, kStoreGlobal + i * 4)
    Which is: 1996488715
  kSentinel
    Which is: 2882382797
store element 11

[  FAILED  ] Gfx1250ExecutionTest.TensorDmaEmptyTensorExtentReadsNothing (711 ms)
[----------] 1 test from Gfx1250ExecutionTest (711 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (711 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] Gfx1250ExecutionTest.TensorDmaEmptyTensorExtentReadsNothing

 1 FAILED TEST

Test Result

After the fix the new tests pass and the full suite is green:

100% tests passed, 0 tests failed out of 3160

Notes: VERDICT: the fix is correct, minimal, and genuinely validated. I made no changes and did not amend the commit. Criticisms below are all outstanding but minor; none justify churning the change.

WHAT I VERIFIED MYSELF

  • git diff origin/develop is exactly two hunks, 62 insertions / 1 deletion. Confined to emulation/; projects/ untouched, no submodule bump. The desc.tensor_dims[dim] != 0 && guard is indeed present at origin/develop.
  • Fail-first is real. I hand-reverted ONLY the source hunk (restoring the exact develop line, leaving the test in place), rebuilt rocjitsu_tests, and ran the new

copy_dense_tensor() bounds-checked each tile coordinate against the
descriptor's tensor extent for that dimension, but skipped the check
when the extent was zero. Zero cannot mean unbounded here:
parse_descriptor() reads a real field for every dimension below rank(),
and rank() for a dense descriptor comes from the tile dimensions, so
there is no dimension inside the rank whose extent went unset. Zero
means the tensor is empty in that dimension and every coordinate in it
is out of bounds.

The consequence was that a descriptor with nothing left to copy -- the
last prefetch of a pipelined loop, where the base has advanced past the
end of the tensor and the remaining extent has counted down to zero --
copied a full tile from beyond the allocation. A load pulled whatever
followed the tensor in memory into LDS; a store wrote the tile over
memory the guest never named.

Bound every dimension below the rank unconditionally. The out-of-bounds
elements then take the path copy_bytes() already had: zero into LDS on a
load, nothing written on a store, which is what the hardware does with a
tile that hangs off the end.

copy_gather_tensor() keeps its check as it is. A gather descriptor's
rank is derived from the tensor extents themselves, so a zero there
genuinely does mean the dimension is absent.

Tested by Gfx1250ExecutionTest.TensorDmaEmptyTensorExtentReadsNothing,
which issues a rank-2 descriptor whose dim1 extent is zero and asserts
the load leaves LDS zeroed and the store leaves the destination at its
sentinel. Before the fix the test saw the out-of-bounds rows in LDS and
the tile written over the sentinel.
@therock-pr-bot

therock-pr-bot Bot commented Aug 18, 2026 •

Copy link
Copy Markdown

✅ All Checks Passed — Ready for Review

Check Status Details
📝 PR Description ✅ Pass —
⛔ Forbidden Files ✅ Pass —
🧪 Unit Test ✅ Pass —
🔎 pre-commit ✅ Pass —
🚫 Draft PR 🔜 To Be Enabled —
🚩 Feature Flag 🔜 To Be Enabled —
📊 Code Coverage 🔜 To Be Enabled —
🤖 therock-pr-bot ✅ Pass —

🎉 All checks passed! This PR is ready for review.

📖 Need help? See the Policy FAQ for details on every check and how to fix failures.

🙋 Wish to Override Policy?

@therock-pr-bot

Copy link
Copy Markdown

🎉 All checks passed! This PR is ready for review.

@amd-arosa

Copy link
Copy Markdown
Contributor Author

Superseded. develop fixed this independently in a659172 ("fix(rocjitsu): honor TDM tensor bounds across iterations", #9936), which landed after this branch's base — it drops the tensor_dims[dim] != 0 && guard and adds in_bounds = !layout.empty(), giving the same semantics plus per-iteration origin handling this PR did not have. Closing in favour of that. The regression test here (TensorDmaEmptyTensorExtentReadsNothing) is not obviously covered by #9936, so I'll offer it separately if it still adds value.

@amd-arosa amd-arosa closed this Aug 18, 2026
@amd-arosa
amd-arosa deleted the users/arosa/rocjitsu/fix/tensor-extent branch August 18, 2026 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant