Skip to content

feat: [rocjitsu] Adding EXEC state tracking for liveness - #7470

Merged
theSK2005 merged 23 commits into
developfrom
users/skushwah/exec-def-kill
Aug 7, 2026
Merged

theSK2005 merged 23 commits into
developfrom
users/skushwah/exec-def-kill

Conversation

@theSK2005

@theSK2005 theSK2005 commented Jun 18, 2026 •

Copy link
Copy Markdown
Contributor

Exposed flags to label instructions that ignore EXEC or write to EXEC so it is accessible by liveness. Then iterate EXEC state per instruction in reverse post order so that liveness VGPR/accVGPR kills can be done properly. Moved some resolve_scalar functions into a shared header to reduce code overlap.

Defer handling instructions that require EXEC to be AllOnes.

Addresses Issue #7025.

@theSK2005
theSK2005 marked this pull request as ready for review June 22, 2026 23:29
@theSK2005
theSK2005 requested review from a team and atgutier as code owners June 22, 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.

This is my first pass of the codegen. Haven't reviewed the analysis yet. Mostly nit-picky things and a couple questions I have that could improve the code if it is feasible.

@theSK2005
theSK2005 force-pushed the users/skushwah/exec-def-kill branch from ec0cf8e to 0126c3d Compare June 23, 2026 20:12
@theSK2005
theSK2005 requested review from Groverkss and accauble June 23, 2026 21:39

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

This overall LGTM.

An agent review flagged a few things that would be good to address:

MINOR (recommended before merge)

  1. exec_state.cpp:131-161 — loop-header-as-scope-entry seeding edge case (soundness-adjacent). A
  block that is both the kernel-scope entry and the target of an in-scope back-edge (loop header at
  offset 0) is classified non-entry and seeded optimistically Full instead of Unknown — the only path
  by which the forward MUST analysis could compute Full where it should be Unknown (→ an unsound
  kill). In practice the absolute first block of a kernel cannot have an in-scope back-edge, so it's
  robustness, not an observed bug. Fix: treat a block as entry-for-seeding if it's the scope leader OR
   has no in-scope predecessor.
  2. RESULT_COPY/RESULT_OR derived by string-matching semantic_class/operation while
  WRITES_EXEC/IGNORES_EXEC come from the AST. A future EXEC-writing copy/or opcode under a class not
  in the hand-list silently loses the combinator flag (degrades safe, but latent drift). Fix: derive
  the combinator from the same AST path so the two flag sets can't diverge.

  NIT

  - exec_state.h:7-13 file-level @details ends mid-sentence ("two-point lattice:") without enumerating
   Full/Unknown.
  - Internal enums (ExecWrite, Combinator) lack explicit : uint8_t underlying type while public
  ExecState has it.
  - binary_translator.cpp:567 benign uint8_t→uint32_t wave-size widening; an assert(wave_size == 32 ||
   64) in the ExecMaskAnalysis ctor would document the invariant.
  - s_cbranch_execz/execnz get IGNORES_EXEC (correct — branches aren't lane-masked) but no READS_EXEC.
   These branches do test EXEC; whether that should mark EXEC live for liveness is a semantics call
  worth deciding. If yes, it's a generator change (emit READS_EXEC for those opcodes).

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

Overall I think this is great. There is still some clean up required. I like the refactor that moves code to the scalar_operand_resolve header but I think @kuhar should weigh in on it once the tests all pass.

@theSK2005

Copy link
Copy Markdown
Contributor Author

This overall LGTM.

An agent review flagged a few things that would be good to address:

MINOR (recommended before merge)

  1. exec_state.cpp:131-161 — loop-header-as-scope-entry seeding edge case (soundness-adjacent). A
  block that is both the kernel-scope entry and the target of an in-scope back-edge (loop header at
  offset 0) is classified non-entry and seeded optimistically Full instead of Unknown — the only path
  by which the forward MUST analysis could compute Full where it should be Unknown (→ an unsound
  kill). In practice the absolute first block of a kernel cannot have an in-scope back-edge, so it's
  robustness, not an observed bug. Fix: treat a block as entry-for-seeding if it's the scope leader OR
   has no in-scope predecessor.
  2. RESULT_COPY/RESULT_OR derived by string-matching semantic_class/operation while
  WRITES_EXEC/IGNORES_EXEC come from the AST. A future EXEC-writing copy/or opcode under a class not
  in the hand-list silently loses the combinator flag (degrades safe, but latent drift). Fix: derive
  the combinator from the same AST path so the two flag sets can't diverge.

  NIT

  - exec_state.h:7-13 file-level @details ends mid-sentence ("two-point lattice:") without enumerating
   Full/Unknown.
  - Internal enums (ExecWrite, Combinator) lack explicit : uint8_t underlying type while public
  ExecState has it.
  - binary_translator.cpp:567 benign uint8_t→uint32_t wave-size widening; an assert(wave_size == 32 ||
   64) in the ExecMaskAnalysis ctor would document the invariant.
  - s_cbranch_execz/execnz get IGNORES_EXEC (correct — branches aren't lane-masked) but no READS_EXEC.
   These branches do test EXEC; whether that should mark EXEC live for liveness is a semantics call
  worth deciding. If yes, it's a generator change (emit READS_EXEC for those opcodes).

Fixed the all the issues except comment #2. I think moving the RESULT_COPY and RESULT_R flags into the AST could be a follow-up PR.

@therock-pr-bot

therock-pr-bot Bot commented Jun 26, 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 Jun 26, 2026 •

Copy link
Copy Markdown

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

@theSK2005 theSK2005 changed the title [rocjitsu] Adding EXEC state tracking for liveness feat: [rocjitsu] Adding EXEC state tracking for liveness Jun 26, 2026
@therock-pr-bot

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.

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

Still need to update a default wave size in exec_state.h.

@theSK2005
theSK2005 requested a review from accauble July 1, 2026 21:37
@theSK2005
theSK2005 requested review from Groverkss and kuhar July 7, 2026 14:47

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

A few comments

@theSK2005
theSK2005 requested a review from kuhar July 13, 2026 21:32
@accauble

Copy link
Copy Markdown
Contributor

@theSK2005 could you rebase please?

@theSK2005
theSK2005 force-pushed the users/skushwah/exec-def-kill branch from dde6c35 to f0d600a Compare July 15, 2026 22:55

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

A couple of comments, the other one is above: #7470 (comment)

@theSK2005
theSK2005 requested a review from kuhar July 20, 2026 17:28
@theSK2005
theSK2005 requested a review from kuhar August 3, 2026 22:15

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

LGTM - I would say that tracking the must be all ones is a good follow-up and not required for this PR.

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

This seems to be ~10% slower on rccl hotswap translation -- we need to bring the overhead down before this can land.

@accauble

accauble commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

This seems to be ~10% slower on rccl hotswap translation -- we need to bring the overhead down before this can land.

Does the rccl translation need the EXEC state tracking for correctness?

@kuhar

kuhar commented Aug 5, 2026

Copy link
Copy Markdown
Member

I found one meaningful optimization: 20a238e

This seems to be ~10% slower on rccl hotswap translation -- we need to bring the overhead down before this can land.

Does the rccl translation need the EXEC state tracking for correctness?

If we can, we should have a very quick check that answers this and decides whether to skip the analysis or not.

@accauble
accauble requested a review from kuhar August 6, 2026 14:09

@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/rocjitsu/src/rocjitsu/analysis/exec_state.h:77

Could we make before_ sparse and store only instructions whose incoming state is Full? before() already returns Unknown for missing entries, and liveness only distinguishes the Full case, so an unordered_set<const Instruction *> full_before_ preserves the query contract while avoiding a map node and state value for every instruction.

I prototyped this as local commit 20a238e3de (5 insertions, 4 deletions). On the exact 224,676,512-byte RCCL object, three CPU-32-pinned runs reduced median CPU time from 184.46 s to 171.64 s (-6.95%) and wall time from 184.53 s to 171.72 s (-6.94%). Median peak RSS was effectively flat: 15,977,508 KiB to 15,977,872 KiB (+0.002%). A matched perf stat run showed task-clock -7.51%, cycles -7.93%, instructions -1.88%, branches -1.95%, branch misses -2.96%, and about 71k fewer page faults. All runs produced the same 224,676,512-byte output with SHA-256 7c843d92dddbe69b1944a84eabd3d8d6a64304c6a84f1a03af638a16f7d15d9b; all 76 focused liveness, EXEC, and gfx1250 translation tests passed.

@theSK2005
theSK2005 force-pushed the users/skushwah/exec-def-kill branch from d511903 to 4cc3f37 Compare August 6, 2026 18:22
@theSK2005
theSK2005 merged commit e92aa6e into develop Aug 7, 2026
46 of 52 checks passed
@theSK2005
theSK2005 deleted the users/skushwah/exec-def-kill branch August 7, 2026 15:35
theSK2005 added a commit that referenced this pull request Aug 7, 2026
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 added a commit that referenced this pull request Aug 7, 2026
Reconciles this branch's evolved EXEC/register-spilling work with develop's
official EXEC-tracking merge (#7470) and picks up develop-only changes
(#9793 GuestKfd, scoped_cfg_edges extraction, analysis-layer additions).

Conflict resolution:
- amdgpu_code_object.{h,cpp} and tests/code/amdgpu_code_object_test.cpp:
  kept this branch's version. Its kernel_descriptor_scan / KernelDescriptorInfo
  refactor supersedes #7470's AmdGpuCodeObject::kernel_wavefront_size and
  ::kernel_entry_text_offsets members, which are removed here.
- patch/instrumentor.cpp: kept this branch's body (scan_kernel_descriptors +
  the kernel_wavefront_size free function), and added develop's
  analysis/exec_state.h include -- required because develop's LivenessAnalysis
  now holds a unique_ptr<ExecMaskAnalysis>, whose complete type is needed
  wherever a LivenessAnalysis is destroyed (instrumentor.cpp constructs one).
- tests/patch/instrumentor_test.cpp: kept this branch's version; develop's
  added cases exercised the removed members (covered here by
  kernel_descriptor_scan_test.cpp instead).

Adopted develop's analysis layer (liveness 4-arg exec signature,
exec_state/def_use, scoped_cfg_edges.{h,cpp}, binary_translator refactor)
which this branch had not modified. Builds clean.
theSK2005 added a commit that referenced this pull request Aug 7, 2026
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.

(cherry picked from commit bc71280)
amd-arosa added a commit that referenced this pull request Aug 7, 2026
Eleven conflicts, all from #7470, which moved the scalar operand resolvers out
of the codegen template and into shared/scalar_operand_resolve.h. The generated
per-arch operand.cpp files now emit only their M0 encoding value and call the
shared header, so ten of the eleven are that substitution and take develop's
side unchanged.

The eleventh is the template those files came from. This branch had added TTMP
routing to the emitted resolvers: encoding values 108..123 name the trap
handler's private scratch file, which hardware banks separately from the wave's
SGPR allocation and which the CP seeds with the dispatch identity rocm-dbgapi
reads back out of the CWSR area. Sending them through read_sgpr()/write_sgpr()
lets a shader that never traps clobber them, and makes the debugger read wave
identity out of whatever SGPR happens to alias. develop's header sends them
there. Take develop's refactor and carry the routing into the header instead,
at all four sites (32- and 64-bit reads, 32- and 64-bit writes), keeping the
file's own literal-selector idiom rather than importing this branch's
kTtmpSelector* constants across the vm/ layering.

Gfx1250B0ToA0Library.ReportsTranslatorDiagnosticsAndRequiredWork and
HsaHotswapHookTest.RendersTranslatorDiagnosticsAndDumpsFailedSource, noted as
pre-existing develop failures in the previous merge, are fixed upstream by
1e3a135 and now pass.
atgutier pushed a commit that referenced this pull request Aug 7, 2026
PR #7470 had a bad merge with PRs #8933 (intended to bring in
register_exec_fn) and #9099 (intended to remove register_exec_fn) in
_generator.py. Prior to PR #7470, develop didn't have this function and
PR #7470 brought it back in when it shouldn't. Regeneration currently
fails on develop, this fixes it. No changes to generated ISA.

## Test Plan

Reran all rocjitsu tests

## Test Result

All pass

## Submission Checklist

- [x] Look over the contributing guidelines at
https://github.com/ROCm/rocm-systems/blob/develop/CONTRIBUTING.md.
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.

6 participants