Skip to content

[rocjitsu] Match gfx1201/gfx1100 DOT2, FP8/BF8 DOT4 and integer DOT half selection - #13691

Open
yashjha123 wants to merge 7 commits into
developfrom
users/yashjha123/rdna4-dot
Open

yashjha123 wants to merge 7 commits into
developfrom
users/yashjha123/rdna4-dot

Conversation

@yashjha123

Copy link
Copy Markdown
Contributor

Motivation

The emulator used CPU floating-point accumulation for F16/BF16-output DOT2 and FP8/BF8 DOT4, which did not match the GPU’s accumulation order and precision. DOT4 also decoded BF8 operands as FP8. This PR reuses and extends the existing DOT/WMMA arithmetic to match hardware rounding, special values and subnormals.

What else was fixed

Some encoded operand controls were also ignored: floating DOT missed accumulator ABS, and integer DOT4/DOT8 ignored non-default source-half selection. These now use shared modifier and selection helpers. Default integer arithmetic and saturation were already correct. The existing F32 DOT arithmetic is retained, with a correction for tiny negative accumulators on GFX12.

Regression tests use gfx1100/gfx1201 captures and cover independent MODE fields, overflow, NaNs, subnormals, combined modifiers and half selection. They exercise SIMD enabled and forced scalar execution, check inactive lanes, and require eligible integer cases to use SIMD. Full test and replay results are pending.

Note: the shared generated code also changes RDNA2 and CDNA1–4 (accumulator ABS, integer half selection), and CDNA5 integer DOT. The gfx12 accumulator rule also reaches RDNA4 VOPD DOT2ACC and WMMA. Only gfx1201 and gfx1100 were measured; other targets follow by extrapolation.

###How it was tested

  • Hardware replay, each with SIMD on and scalar forced:
Corpus gfx1201 gfx1100
DOT corpus 80/80 (develop 55) 69/69 (develop 59)
Follow-up capture* 42/42 (develop 2) 30/30 (develop 2)
Main VALU corpus +6 variants, none lost +6, none lost
  • ABS+NEG on the accumulator, MODE values that change one input/output bit at a time, and integer OP_SEL combined with NEG and CLAMP.
  • Decoded test cases taken from the captures for both GPUs, including ABS/NEG order, subnormal operands under each MODE, and integer cases that check the SIMD path is taken.
  • Mutation checks: applying NEG before ABS, or dropping ABS, fails exactly those cases.

Issue tracking

#12467

…alf selection

- True16 V_DOT2_F16_F16 / V_DOT2_BF16_BF16 run one packed step of each
  target's DOT/WMMA datapath; MODE rounding and denormal fields do not
  apply and FP16_OVFL clamps F16 only. Remove fp_mode::dot2_f16/dot2_bf16.
- RDNA4 V_DOT4_F32_{FP8,BF8}_{FP8,BF8} run through the GFX12 DOT datapath:
  the four products align on one grid and an invalid product returns the
  factor-NaN payload.
- NEG_HI on the F32 DOT accumulator is ABS, applied before NEG through the
  shared source_modifier stage in the scalar and SIMD paths. On GFX12 a tiny
  negative C subtracts one unit when the grid is at or below 2^-126.
- OP_SEL/OP_SEL_HI select the 16-bit source halves of integer DOT4/DOT8,
  before signedness and CLAMP, in the scalar and SIMD paths.
- Add the BF16 layout to fp_format.h and a VOP3P_DOT_INT SIMD path id.

Shared generated bodies also change RDNA2 and CDNA1-4 (accumulator ABS,
integer selection); CDNA5 integer DOT changes directly. The GFX12
accumulator rule also reaches RDNA4 VOPD DOT2ACC and WMMA. Decoded cases
come from gfx1201 and gfx1100 captures; other targets are extrapolated.
@yashjha123
yashjha123 requested review from a team and atgutier as code owners October 17, 2026 23:33
Copilot AI balanced review requested due to automatic review settings October 17, 2026 23:33
@therock-pr-bot

therock-pr-bot Bot commented Oct 17, 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.

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.

🟡 Changes recommended

Clamped integer tests require SIMD on configurations where the existing AVX-512 workaround deliberately selects scalar execution.

1 open issue
What changed in this PR

Updates rocjitsu’s DOT emulation to match gfx1100/gfx1201 hardware behavior, extending the floating-point accuracy work in #12467.

Changes:

  • Reuses architecture-specific arithmetic for packed DOT2 and FP8/BF8 DOT4.
  • Corrects accumulator modifiers and integer source-half selection.
  • Adds capture-based regressions covering arithmetic, modifiers, and execution paths.
File Description
emulation/​rocjitsu/​tests/​valu_fp_mode_test.cpp Adds capture-based DOT regressions.
emulation/​rocjitsu/​tests/​source_modifier_test.cpp Tests BF16 sign modifiers.
emulation/​rocjitsu/​tests/​instruction_execution_harness_test.cpp Updates BF16 and accumulator expectations.
emulation/​rocjitsu/​lib/​rocjitsu/​src/​rocjitsu/​isa/​arch/​amdgpu/​shared/​simd_glue.h Updates SIMD selection, modifiers, and tracking.
emulation/​rocjitsu/​lib/​rocjitsu/​src/​rocjitsu/​isa/​arch/​amdgpu/​shared/​gfx12_dot.h Extends GFX12 DOT arithmetic.
emulation/​rocjitsu/​lib/​rocjitsu/​src/​rocjitsu/​isa/​arch/​amdgpu/​shared/​gfx11_dot2.h Documents packed DOT2 reuse.
emulation/​rocjitsu/​lib/​rocjitsu/​src/​rocjitsu/​isa/​arch/​amdgpu/​shared/​fp_mode.h Removes superseded DOT2 helpers.
emulation/​rocjitsu/​lib/​rocjitsu/​src/​rocjitsu/​isa/​arch/​amdgpu/​shared/​fp_format.h Adds BF16 format traits.
emulation/​rocjitsu/​lib/​rocjitsu/​src/​rocjitsu/​isa/​arch/​amdgpu/​generated/​shared/​execute_shared.h Updates shared DOT executors.
emulation/​rocjitsu/​lib/​rocjitsu/​src/​rocjitsu/​isa/​arch/​amdgpu/​generated/​rdna4/​vop3p_exec.cpp Applies RDNA4 DOT fixes.
emulation/​rocjitsu/​lib/​rocjitsu/​src/​rocjitsu/​isa/​arch/​amdgpu/​generated/​rdna4/​vop3_exec.cpp Uses GFX12 packed DOT2 arithmetic.
emulation/​rocjitsu/​lib/​rocjitsu/​src/​rocjitsu/​isa/​arch/​amdgpu/​generated/​rdna3/​vop3_exec.cpp Uses GFX11 packed DOT2 arithmetic.
emulation/​rocjitsu/​lib/​rocjitsu/​src/​rocjitsu/​isa/​arch/​amdgpu/​generated/​rdna3_5/​vop3_exec.cpp Reuses GFX11 packed DOT2 arithmetic.
emulation/​rocjitsu/​lib/​rocjitsu/​src/​rocjitsu/​isa/​arch/​amdgpu/​generated/​cdna5/​vop3p_exec.cpp Applies integer half selection.
emulation/​rocjitsu/​lib/​python/​amdisa/​tests/​test_packed_codegen.py Tests generated DOT behavior.
emulation/​rocjitsu/​lib/​python/​amdisa/​tests/​test_generator_profile_gates.py Updates packed DOT2 assertions.
emulation/​rocjitsu/​lib/​python/​amdisa/​codegen/​execute/​packed.py Generates corrected DOT operations.
emulation/​rocjitsu/​lib/​python/​amdisa/​codegen/​execute/​__init__.py Passes architecture and selection settings.
emulation/​rocjitsu/​lib/​python/​amdisa/​codegen/​_generator.py Updates dispatch and required includes.

Review effort: Balanced

Comment thread emulation/rocjitsu/tests/valu_fp_mode_test.cpp Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

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

I think it would help to use operand and instruction names that expose their roles in the new mixed-format code and capture tables:

  • In emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/isa/arch/amdgpu/shared/gfx12_dot.h:144, use Src0Format/Src1Format for the A/B template types and the corresponding aliases in gfx12_dot4_f32_fp8. This makes it easier to track which input uses FP8 or BF8.
  • In emulation/rocjitsu/tests/valu_fp_mode_test.cpp:2893, use src0/src1/acc for Lane::{a,b,c} and the matching add parameters. Around line 3130, names such as dot2_f32_f16 and dot4_u8 would distinguish opcode constants from format/type names like f16 and u8.

The capture values can stay as they are; these names would make their interpretation easier to check.

We should record the new captures' provenance and measured scope in the repository. emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/isa/arch/amdgpu/shared/gfx12_dot.h:142 points readers to tests/fixtures/float_dot/README.md, but that README only documents the existing F16/BF16 DOT2/WMMA fixtures.

Please document the cards, SDK/driver and capture procedure for the new inline true16 DOT2, FP8/BF8 DOT4 and integer modifier cases in valu_fp_mode_test.cpp. Also distinguish measured gfx1100/gfx1201 behavior from the integer half-selection rule extrapolated to RDNA2/CDNA (lib/python/amdisa/codegen/execute/packed.py:1411), and record which callers exercise the changed accumulator-floor rule. The new gfx1201 BF16 WMMA probe supplies evidence for that caller; VOPD should remain identified as extrapolated unless separately measured.

For the older NEG_HI/NEG rows (tests/valu_fp_mode_test.cpp:3113), describe the capture batch and its joint rounding-field sweep instead of the unexplained “before 10-17” reference. This would make the evidence and its limits recoverable without the PR discussion.

static constexpr uint16_t infinity = Bf16 ? 0x7f80 : 0x7c00;
/// @brief Factor encoding: exponent and fraction widths. OCP E4M3 has no
/// infinity; S.1111.111 is its only NaN.
template <int ExponentBits, int FractionBits, bool OcpE4m3 = false> struct FactorFormat {

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.

I think it would help to derive F16Factor and Bf16Factor from fp_format::F16 and fp_format::BF16's kExponentBits/kMantissaBits. This PR adds the BF16 format traits but also repeats both layouts here as <5, 10> and <8, 7>. Reusing those traits would keep the layout definitions in one place; matching their constant names would also make the relationship easier to follow.

/// packing op_sel == 0 && op_sel_hi == 3); neg / neg_hi flip the src0/src1
/// product-operand signs and neg bit 2 flips the accumulator. The encoded CLAMP
/// product-operand signs; on the accumulator neg_hi bit 2 is ABS, applied before
/// neg bit 2, as in the scalar body. The encoded CLAMP

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.

Nit: could we put @tparam Fmt on its own Doxygen line and reflow the final paragraph? It is currently attached to the NaN-payload sentence, with pk_fma slices split awkwardly across lines. Separating the parameter documentation would make this helper's contract easier to scan.

const uint32_t expected = arch == ROCJITSU_CODE_ARCH_RDNA4 ? lane.gfx1201 : lane.gfx1100;
for (const uint32_t mode : lane.modes) {
char suffix[16];
std::snprintf(suffix, sizeof(suffix), "Mode%X", mode);

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.

We should use std::format("Mode{:X}", mode) for the suffix here and in dot_family_cases() around line 3274. It preserves the case names while removing the two fixed-size buffers and the new <cstdio> dependency, and follows the project's formatting idiom.

# Only RDNA4 has these; gfx1201 runs them through its DOT datapath.
if dot_accumulation is not FloatDotAccumulation.GFX12:
raise ValueError(f'{instruction} needs the GFX12 DOT accumulation model')
formats = instruction.upper().removeprefix('V_DOT4_F32_').split('_')

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 might be easier to maintain if the FP8/BF8 operand formats lived on InstructionSemantics, as they already do for packed conversions (semantics.py:889). All four DOT4 names currently map to one class, so both dispatch sites pass the mnemonic through just for gen_dot4 to parse it again. Carrying the format pair in operation would keep instruction classification in the semantic layer and remove the new instruction parameter and name parsing here.

using namespace gfx12_dot_detail;
// 8-bit factors align all products on one grid, and an invalid product
// returns the factor-NaN payload. 16-bit factors align products in pairs.
constexpr bool kByteFactors = A::exponent_bits + A::fraction_bits < 8;

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.

Optional: make product grouping and the invalid-product payload explicit arithmetic-policy inputs to gfx12_dot_terms. kByteFactors currently chooses both from the left operand's width, although the documented evidence is specifically for gfx1201 FP8/BF8 DOT4. Having the DOT4 and half-format wrappers select those two policies would distinguish instruction behavior from encoding layout. Current callers are correct; this is about making the shared DOT/WMMA core's assumptions visible.

// that tiny C.
const int c_floor = Packed && !Bf16 ? -14 : -126;
const int grid = std::max(product_grid, std::max(c_floor, c.leading_exponent()) - 26);
int64_t total = align(c, grid, grid > c_floor);

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.

It would be good to retain one F32-output and one BF16-output WMMA witness for this accumulator-floor change. The existing WMMA fixtures pass with either rule, while the gfx1201 probe matched the new rule in all 16,384 cases per opcode and distinguished it in 56 F32 and 14 BF16 cases.

For wave32, use A with only k=0 nonzero, uniform B and uniform C:

Instruction A[k=0] B C Hardware/new Old rule
v_wmma_f32_16x16x16_bf16 0x2900 0x2280 0x8000082d 0x0bffffff 0x0c000000
v_wmma_bf16_16x16x16_bf16 0x3800 0x1400 0x8051 0x0c7f 0x0c80

Adding these to the decoded WMMA tests would protect the changed behavior. The measurements support the implementation; this is a regression-coverage request.

…oduct policy explicitly

- F16Factor and Bf16Factor come from fp_format::F16/BF16; factor constants use
  fp_format's kExponentBits/kMantissaBits names.
- gfx12_dot_terms takes Src0Format/Src1Format and a ProductPolicy naming the
  product grouping and invalid-product NaN. The half-format and FP8/BF8 DOT4
  wrappers choose them, instead of inferring both from the factor width.

No behaviour change: DOT replay outputs are byte-identical.
…th std::format

- The captured DOT lanes use src0/src1/acc, and the opcode constants read as
  instructions (dot2_f32_f16, dot4_u8, ...) rather than formats.
- Build the "Mode<hex>" case suffix with std::format and drop <cstdio>.
- Give @tparam its own line in try_execute_vop3p_dot_f16_simd's comment.

Test names and values are unchanged.
V_DOT4_F32_{FP8,BF8}_{FP8,BF8} now record their src0/src1 formats in the
semantic operation, as the packed FP8/BF8 conversions do. gen_dot4 reads the
operation instead of re-parsing the mnemonic, so both dispatch sites drop the
instruction-name argument.

Regenerated sources are unchanged.
Add F32-output and BF16-output V_WMMA_*_16X16X16_BF16 cases, captured on
gfx1201 wave32 with only k=0 of A nonzero: 0x0bffffff and 0x0c7f, where the
old rule gave 0x0c000000 and 0x0c80. Restoring the old rule fails only this
test. The probe matched the new rule on all 16,384 cases per opcode.

Rename Bf8Bf8TinyNegativeAccumulator to Bf8Bf8NegativeSubnormalAccumulator:
FP8/BF8 products never reach the -126 grid, so that lane shows C read
unflushed, not the floor unit. Point the DOT capture comments at the fixtures
README instead of a capture date.
Extend tests/fixtures/float_dot/README.md with the cards, ROCm and driver
versions, procedure and MODE coverage of the inline DOT captures; separate
the behaviour measured on gfx1100/gfx1201 from what RDNA2, CDNA1-4 and CDNA5
inherit through shared generated bodies; and list which callers of the
negative-C floor rule were measured (VOP3P DOT2_F32_BF16, BF16 WMMA) and
which are extrapolated (true16 DOT2_BF16_BF16, VOPD DOT2ACC_F32_BF16).

This branch has not been deployed

No deployments
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.

3 participants