Skip to content

fix(rocjitsu): D16 Loads Count as Partial Defs - #8344

Merged
theSK2005 merged 21 commits into
developfrom
users/skushwah/d16-partial-load
Aug 8, 2026
Merged

theSK2005 merged 21 commits into
developfrom
users/skushwah/d16-partial-load

Conversation

@theSK2005

@theSK2005 theSK2005 commented Jul 9, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

D16 memory loads are 16 bit writes into VGPRs. These operations currently are seen as full defs by liveness analysis since VDST is only a dst and not a src and has a 32 bit operand size so PR #7979 won't cover it.

Technical Details

Added check in _generator.py's _dst_is_also_source to cover d16 load operations and have codegen write VDST as both a dst and a src.

Fixed existing semantics.py bug that didn't use _BUFFER_FORMAT_MAP for derive_mubuf which left many instructions unimplemented and not properly flagged.

Test Plan

  • Verify InstDefUse on decoded D16 instructions sees VDST as a src and a dst.
  • Verify all other tests pass.

Test Result

All tests pass

Submission Checklist

@theSK2005
theSK2005 requested review from a team and atgutier as code owners July 9, 2026 18:55
@therock-pr-bot

therock-pr-bot Bot commented Jul 9, 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

therock-pr-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown

Pre-commit check failed

⛔ pre-commit failed

Please run locally:

  • python -m pip install pre-commit
  • pre-commit install
  • pre-commit run --all-files --show-diff-on-failure

This repo uses .pre-commit-config.yaml.

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

The risk here is that _D16_LOAD_CLASSES advertises buffer D16 coverage, but the generated source operands still do not include the preserved destination for MUBUF/VBUFFER loads. _dst_is_also_source() can return true for buffer_load_d16_u8, yet the emission gates at emulation/rocjitsu/lib/python/amdisa/codegen/_generator.py:1810 and emulation/rocjitsu/lib/python/amdisa/codegen/_generator.py:5215 only accept output operands named vdst or sdst; buffer loads use vdata. The generated emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/isa/arch/amdgpu/rdna4/vbuffer.cpp:867 still has vdata only in dst_operands_, with sources starting at vaddr, so liveness still treats those D16 buffer loads as full defs. If buffer loads are in scope, please include the vdata path and regenerate the affected files; otherwise remove buffer_load/tbuffer_load from the D16 class set so the contract matches the generated behavior.

@kuhar

kuhar commented Jul 9, 2026

Copy link
Copy Markdown
Member

There are also some pytest failures

@theSK2005
theSK2005 requested a review from kuhar July 10, 2026 18:59
@theSK2005 theSK2005 assigned accauble and unassigned accauble Jul 10, 2026
@theSK2005
theSK2005 requested a review from accauble July 10, 2026 18:59
@therock-pr-bot

Copy link
Copy Markdown

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

@theSK2005
theSK2005 force-pushed the users/skushwah/d16-partial-load branch from d32872d to ebad804 Compare July 14, 2026 20:37
theSK2005 added a commit that referenced this pull request Jul 15, 2026
## Motivation

Adds the destination register for SDWA (dst_unused:preserved) and DPP
(partial mask) instructions as a source so that InstDefUse and liveness
analysis work soundly. Addresses issue #7033. PR #8344 is a followup.

## Test Plan
Wrote some tests cases that decode SDWA and DPP instructions that do and
don't keep prior register values and checked if uses were stored
properly.

## Test Result
Passed new tests and all previous tests.

---------

Co-authored-by: Allyson Cauble-Chantrenne <acaublec@amd.com>
@accauble

Copy link
Copy Markdown
Contributor

@theSK2005 could you rebase please?

@newling

newling commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

Just to check I understand the description

D16 memory loads are 16 bit writes into VGPRs. These operations currently are seen as full defs by liveness analysis since VDST is only a dst and not a src and has a 32 bit operand size so PR #7979 won't cover it.

My understanding is that before this PR:

  • the destination register is seen as having 32-bits written, and 0-bits read.

and then after this PR, it is either option A or B below?
(A) the destination register is seen as having 16-bits written, and other 16-bits read
(B) (conservative) the destination register is seen as having 32-bits read, then 32-bits written

This PR caught my attention because I've encountered a semantically problem in a parallel place in rocjitsu #8628.

@theSK2005

Copy link
Copy Markdown
Contributor Author

Just to check I understand the description

D16 memory loads are 16 bit writes into VGPRs. These operations currently are seen as full defs by liveness analysis since VDST is only a dst and not a src and has a 32 bit operand size so PR #7979 won't cover it.

My understanding is that before this PR:

  • the destination register is seen as having 32-bits written, and 0-bits read.

and then after this PR, it is either option A or B below? (A) the destination register is seen as having 16-bits written, and other 16-bits read (B) (conservative) the destination register is seen as having 32-bits read, then 32-bits written

This PR caught my attention because I've encountered a semantically problem in a parallel place in rocjitsu #8628.

This PR doesn't change the operand sizes, so it's still seen as a 32-bit write and 0-bit read. What this PR changes is that the dst register is counted as an implicit use so that they're surfaced to liveness analysis. If you look at the regenerated ISA on this PR, it's all implicit use functions.

@theSK2005
theSK2005 force-pushed the users/skushwah/d16-partial-load branch from ebad804 to fac570e Compare July 15, 2026 23:29

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

I have one minor concern but otherwise LGTM.

@theSK2005
theSK2005 force-pushed the users/skushwah/d16-partial-load branch from fac570e to 42aa6b0 Compare July 29, 2026 21:27

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

Original anchor: emulation/rocjitsu/lib/python/amdisa/codegen/_generator.py:2784

Can we make the FORMAT D16 cases consistent before this lands? The current predicate only admits num_elems == 1, and the generated output shows two holes in that model: tbuffer_load_format_d16_x gets an implicit_uses() override, but buffer_load_format_d16_x / RDNA4 buffer_load_d16_format_x do not, while odd forms like tbuffer_load_format_d16_xyz write 3 halfwords into a 64-bit vdata and leave the upper half of the second VGPR preserved. This means liveness can still treat real FORMAT D16 loads as full defs. I think we should either model those preserved reads (for example, emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/isa/arch/amdgpu/cdna3/mubuf.cpp:246, emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/isa/arch/amdgpu/rdna4/vbuffer.cpp:228, and emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/isa/arch/amdgpu/cdna3/mtbuf.cpp:443) and add decode tests for *_format_d16_x and *_format_d16_xyz, or explicitly document/test why these formats are out of scope.

At emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/isa/arch/amdgpu/gfx1250/vflat.cpp:316, the D16 preserved-destination read is emitted only as implicit_uses(). On gfx1250, InstDefUse resolves VGPR implicit reads with implicit_use_operands() and then drops RegClass::VGPR from the flat implicit_uses() result, so this vdst dependency is lost for banked VGPR liveness. We should emit the operand-backed implicit_use_operands() twin for D16 load destinations on VGPR-MSB profiles, and add a gfx1250 decode/liveness test for this path.

@newling

newling commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Agent review at https://github.com/newling/agent-public-reviews/blob/main/rocm-systems/review_pr8344.md highlights 2 actionable items

gfx1250’s bank-aware liveness path does not receive the new use, and legacy MUBUF format-D16 loads are not recognized.

Related to earlier discussion (from 2 weeks ago... apologies for my glacial response time on this) longer term I wonder if we should be modeling this at the byte level rather than the dword (4-byte) level. Depending on what tools (consan?) use this, it might be necessary. For future consideration

@newling

newling commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Agent review says there is just 1 outstanding issue from a previous review (not sure whose), please take a look and either address it or say if it's not valid: https://github.com/newling/agent-public-reviews/blob/main/rocm-systems/review_pr8344_followup.md#1-preserve-d16-destination-reads-in-gfx1250-bank-aware-liveness

@theSK2005

Copy link
Copy Markdown
Contributor Author

Agent review says there is just 1 outstanding issue from a previous review (not sure whose), please take a look and either address it or say if it's not valid: https://github.com/newling/agent-public-reviews/blob/main/rocm-systems/review_pr8344_followup.md#1-preserve-d16-destination-reads-in-gfx1250-bank-aware-liveness

yep, I'm working on fixing that atm

@theSK2005
theSK2005 requested a review from kuhar July 31, 2026 00:58
@newling

newling commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

yep, I'm working on fixing that atm

Thanks. LGTM now, no more comments/questions on my side. I'll let one of the main reviewers listed make any final reviews and stamp when ready

@kuhar kuhar 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 with two minor comments

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

[MAJOR] /tmp/pr8344/emulation/rocjitsu/lib/python/amdisa/semantics.py:2090
— D16 FORMAT classification activates incorrect load/store execution

Reasoning: Adding _BUFFER_FORMAT_MAP to MUBUF derivation changes
previously unimplemented BUFFER FORMAT operations into executable memory
operations. The execution pipeline does not implement the packed layout—
two 16-bit components per VGPR—that the new semantics describe.

Evidence:

  • /tmp/pr8344/emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/vm/amdgpu/
    memory_pipeline.cpp:137 uses floor division for the destination VGPR
    count despite its “rounded up” comment.

  • Lines 169–194 copy only two bytes at each four-byte VGPR offset and
    preserve the high half of every visited register.

  • Consequently, D16 XY writes only X and preserves the old high half
    instead of writing Y. D16 XYZ calculates one destination VGPR for six
    bytes and never writes vdata+1, despite its generated two-register
    definition and preserve-read of the last register at /tmp/pr8344/
    emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/isa/arch/amdgpu/rdna4/
    vbuffer.cpp:442.

  • Stores are also wrong: /tmp/pr8344/emulation/rocjitsu/lib/rocjitsu/src/
    rocjitsu/isa/arch/amdgpu/rdna4/vbuffer.cpp:558 reads the low half of the
    same VGPR for both XY components. XYZ and XYZW similarly repeat low
    halves rather than extracting packed components.

  • The added tests validate semantic metadata and def/use sets, but never
    execute multi-component D16 loads or stores.

Suggested fix: Either keep BUFFER FORMAT execution unclassified while
deriving partial-definition metadata separately, or implement packed-D16
execution comprehensively: ceil the VGPR count, pack/unpack two components
per dword, and preserve only the unused half of the final register for odd
component counts. Cover normal and OOB completion, plus XY/XYZ/XYZW load
and store execution tests using distinct halfword values.

Confidence: High.

[MAJOR] /tmp/pr8344/emulation/rocjitsu/lib/python/amdisa/15:42:07 [43/761]
— RDNA4 typed D16 loads remain missing from the fix

Reasoning: RDNA4 combines untyped and typed buffer instructions under
ENC_VBUFFER, but VBUFFER is routed only to derive_mubuf, which recognizes
BUFFER
, not TBUFFER_. Therefore typed D16 X and XYZ loads receive no
preserved-destination use, leaving DBT liveness unsound.

Evidence:

  • _derive_mubuf accepts only BUFFER prefixes at /tmp/pr8344/emulation/
    rocjitsu/lib/python/amdisa/semantics.py:2087.

  • An exact-head semantic probe classified both TBUFFER_LOAD_D16_FORMAT_X
    and ...XYZ under ENC_VBUFFER as nop.

  • RDNA4 X at /tmp/pr8344/emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/isa/
    arch/amdgpu/rdna4/vbuffer.cpp:3394 defines vdata but has no
    implicit_uses() override.

  • XYZ at /tmp/pr8344/emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/isa/
    arch/amdgpu/rdna4/vbuffer.cpp:3442 defines vdata:vdata+1 but does not
    preserve-read the unused half of the final register.

  • These are the unified-encoding equivalents of the pre-RDNA4 TBUFFER
    instructions that this PR does handle.

Suggested fix: Give VBUFFER derivation support for both BUFFER and TBUFFER
families, or detect partial definitions independently of execution
classification. Regenerate RDNA4 and add real-decode def/use tests for
typed D16 X, XY, XYZ, and XYZW.

Confidence: High.

[MINOR] /tmp/pr8344/emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/isa/arch/
amdgpu/cdna1/mubuf.cpp:1470 — LDS-destination loads falsely keep vdata
live

Reasoning: On older MUBUF encodings, inst_.lds redirects the loaded value
exclusively to LDS. The new hook nevertheless unconditionally reports the
encoded vdata VGPR as a preserved-destination read.

Evidence:

  • The implicit use is unconditional.

  • The LDS path at /tmp/pr8344/emulation/rocjitsu/lib/rocjitsu/src/
    rocjitsu/isa/arch/amdgpu/cdna1/mubuf.cpp:1477 sets lds_dst, does not
    establish a VGPR destination, and returns.

  • LDS completion is selected at /tmp/pr8344/emulation/rocjitsu/lib/
    rocjitsu/src/rocjitsu/vm/amdgpu/memory_pipeline.cpp:126.

  • This cannot under-approximate liveness, but it creates a false live
    range and can unnecessarily exclude a DBT scratch register.

Suggested fix: For encodings with an LDS field, emit the D16 implicit use
only when !inst_.lds. Add def/use tests for the same opcode with LDS clear
and set.

Confidence: High.

theSK2005 and others added 2 commits August 5, 2026 17:40
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@theSK2005
theSK2005 requested a review from atgutier August 6, 2026 15:44

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

The risk here is that D16 FORMAT loads/stores decode with GPUMEM operands but are not marked as memory ops. At emulation/rocjitsu/lib/python/amdisa/codegen/_generator.py:7116, _MEM_CLASSES includes buffer_load and buffer_store but not the new buffer_load_format_d16 or buffer_store_format_d16 classes; the generated emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/isa/arch/amdgpu/rdna4/vbuffer.cpp:348 constructors set gpumem but never flags_ |= MEMORY_OP. We should either add both metadata-only classes to the memory flag contract or leave an explicit test/comment if Instruction::is_memory_op() is meant to return false for these memory instructions.

It would help to tighten this D16 FORMAT liveness test block in a couple of targeted spots. emulation/rocjitsu/tests/analysis/liveness_test.cpp:4224 only checks !uses.contains({VGPR, 5, 2}); since RegisterSet::contains requires every lane in the range, a regression that reads only v5 or only v6 would still pass, so please assert both single registers are absent. Also, the new VBUFFER typed path is covered only by tbuffer_load_d16_format_x at emulation/rocjitsu/tests/analysis/liveness_test.cpp:4280; adding one tbuffer_load_d16_format_xyz decode would lock in the odd-count typed case where only the last VGPR is preserved.

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

Approving conditioned on fixing this minor issue and @kuhar's recent comments.

@theSK2005
theSK2005 requested a review from kuhar August 6, 2026 23:28

@kuhar kuhar 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 % two comments

theSK2005 and others added 7 commits August 6, 2026 19:45
…-partial-load

# Conflicts:
#	emulation/rocjitsu/lib/python/amdisa/codegen/_generator.py
#	emulation/rocjitsu/tests/analysis/liveness_test.cpp
PR #7470 had a bad merge with PRs #8933 and #9099 in _generator.py. Regeneration
currently fails on develop, this fixes it. No changes to generated ISA.
@theSK2005
theSK2005 merged commit 2e9f455 into develop Aug 8, 2026
29 checks passed
@theSK2005
theSK2005 deleted the users/skushwah/d16-partial-load branch August 8, 2026 01:03
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.

5 participants