Repository navigation
[AIROCMLIR-1292] [EXTERNAL] Do not stagger CDNA4 padded layouts over rows that do not exist - #508
Conversation
pabloantoniom
left a comment
There was a problem hiding this comment.
This makes sense to me, it looks like a genuine bug in Triton upstream...Could you create a PR in https://github.com/triton-lang/triton ? They should have more context and they might be able to give more valuable feedback
Sure, I've opened the upstream PR here triton-lang/triton#11890 |
erizheng-amd
left a comment
There was a problem hiding this comment.
I can confirm this fixed the recent gemm tuning failures observed on gfx950
0ade6a1 to
114e597
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Add wide-row regression coverage and correct the patch index placement.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Open (2)
What changed in this PR
Fixes CDNA4 padded-layout generation for rows wider than a warp, preventing gfx950 compiler aborts.
Changes:
- Replaces truncating divisions with scaled comparisons.
- Prevents staggering across nonexistent rows.
- Records the downstream Triton patch.
| File | Review |
|---|---|
triton-patches/triton-patch-content.txt |
Documents the patch; index entry is misplaced. |
triton-patches/patch11890.patch |
Records the vendored Triton fix. |
external/triton/third_party/amd/lib/TritonAMDGPUTransforms/Utility.cpp |
Corrects layout guards; the triggering wide-row case lacks regression coverage. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Verdict: COMMENT · Findings: 3 (0 Critical, 2 Major, 1 Minor)
Scope
Three files: a downstream fix to composePaddedLayoutForAsyncCopyCDNA4 in the vendored Triton tree (external/triton/third_party/amd/lib/TritonAMDGPUTransforms/Utility.cpp), the matching record triton-patches/patch11890.patch, and an entry in triton-patches/triton-patch-content.txt.
The code change itself looks correct. Both guards previously computed warpSize / contigLanes with integer division, which truncates to zero once a tile row spans more than a warp of vectors (contigLanes > warpSize); rescaling by contigLanes on the other side of the comparison is the right exact-arithmetic rewrite and is a no-op whenever contigLanes divides warpSize (it always does here, since contigDim and vecSize are powers of two). The extra nonContigDim >= bestWrap term is genuinely needed: the rescaled guard alone still admits nonContigDim == 4 at contigLanes == 256, which would stagger over 16 rows that do not exist.
Findings
triton-patches/triton-patch-content.txt:36— the new filename is inserted between thepatch-gfx1310-isa-family.patchheading and its description body, duplicating the full entry added at the bottom of the file.external/triton/.../Utility.cpp:281— no lit coverage added for the fixed path.external/triton/.../Utility.cpp:258— the rewrite carries over a latent division by zero whencontigLanes == 0.
Notes
- Commit hygiene is correct: the vendored-tree commit carries the
[EXTERNAL]prefix, the record commit is separate, andpatch11890.patchmatches the[EXTERNAL]commit diff hunk-for-hunk. - No rocMLIR back-port note needed — both touched trees (
external/triton/,triton-patches/) are on the rocmlirTriton-only path list. - Follow-up (out of scope, and acknowledged in the patch record's "3 that remain"):
wrapcan still exceednonContigDimafter this change. WithwarpSize=64,contigLanes=256,wrap=8,nonContigDim=2, the rescaled conflict guard passes (512 >= 512),useBestWrapis correctly declined, and the "Add rows [0, wrap]" loop atUtility.cpp:303still emits bases for rows 2 and 4. Awrap = std::min(wrap, nonContigDim)clamp (or a bail-out) before the bases loop would close that arm too. - The PR description's Test Result section links to an internal Jenkins host. Per the checklist's Critical bullet on internal-only hyperlinks — which applies even though this repo is private today — please replace it with a plain-text job/run reference.
CI status
Nothing red. Jenkins, Build and Test, MIGraphX and Code coverage are still pending at the time of review; re-check before merge.
There was a problem hiding this comment.
can you add a lit test for this?
There was a problem hiding this comment.
also an e2e test (rocmlirTriton)
There was a problem hiding this comment.
Added both, the lit test from the upstream PR, and mlir/test/fusion/pr-e2e/rock-gemm-cdna4-padded-layout-wide-row.mlir, which runs the weekly config plus 2-row and 4-row tiles end to end on gfx950
| unsigned haveRowsScaled = nonContigDim * contigLanes; | ||
| unsigned xWayConflicts = | ||
| (nonContigDim >= requiredRows) | ||
| (haveRowsScaled >= requiredRowsScaled) |
There was a problem hiding this comment.
looks good to me, it's equivalent for non-crash cases of the previous version. But I'm not familiar with this code.
There was a problem hiding this comment.
nit: I wonder if adding a comment about the non-scaled comparison would make the code easier to read.
There was a problem hiding this comment.
After the upstream review the fix changed to a clamp of contigLanes to [1, warpSize], so both guards keep their original form, and the clamp has a short comment. It's still equivalent for everything that compiled before, 55 of 55 bit identical
| unsigned bestWrap = 16; | ||
| if (nonContigDim >= warpSize / contigLanes * bestWrap && bestWrap > wrap) { | ||
| if (nonContigDim >= bestWrap && | ||
| nonContigDim * contigLanes >= warpSize * bestWrap && bestWrap > wrap) { |
There was a problem hiding this comment.
nit: nonContigDim >= std::max(bestWrap, warpSize * bestWrap / contigLanes),
There was a problem hiding this comment.
That comparison is gone with the clamp, the guard is back to its original form
114e597 to
fe61ad7
Compare
|
Updated to follow the upstream review on triton-lang/triton#11890 the fix is now a single clamp of contigLanes to [1, warpSize] instead of the scaled comparisons. In the 70-combination gfx950 sweep it takes aborts from 8 to 0 (the scaling left 3), and everything that compiled before produces bit identical code. Also added the upstream lit test and a gfx950 E2E test, and fixed the index entry |
There was a problem hiding this comment.
Verdict: COMMENT · New findings: 1 (0 Critical, 1 Major, 0 Minor)
Scope
Fixes a gfx950 compiler abort in composePaddedLayoutForAsyncCopyCDNA4. When a tile row spans more vectors than a warp has lanes, contigDim / vecSize exceeded warpSize (and could truncate to 0), so requiredRows and the useBestWrap guard both degenerated and the pass emitted a broadcasting layout that PaddedSharedEncodingAttr::verify rejects. The head clamps contigLanes to [1, warpSize] at Utility.cpp:243 and leaves the two downstream guards untouched. Six files: the Triton fix plus its upstream lit test (one [EXTERNAL] commit), and the patch record, index entry, gfx950 E2E test, and its lit.local.cfg gate (one downstream commit).
Findings
One documentation-only Major: the PR description describes a different fix than the one implemented (Utility.cpp:243). No code change requested.
Re-review status
All three findings from the previous review are fixed:
patch11890.patchis now at the end of the ordered apply list intriton-patches/triton-patch-content.txt, no longer nested inside another patch's section.- Lit coverage was added (
amd-pipeline-padded-layout-wide-row-gfx950.mlir) and is carried in the patch record, so a future subtree bump can't silently drop it. - The
contigLanes == 0division hazard is closed by the clamp's lower bound.
Notes
I hand-verified the decline path for the three configs in the E2E test. For mPerBlock=1, kPerBlock=2048 (f16, kWidth=8): contigLanes clamps 256 to 64, wrap = 8, requiredRows = 8, and with nonContigDim = 1 the conflict estimate is 4, so the function returns {} instead of building an invalid layout. mPerBlock=2 and mPerBlock=4, kPerBlock=1024 likewise decline. Inputs already in [1, warpSize] are bit-identical, consistent with the "55 of 55 identical" sweep in the description.
std::clamp needs <algorithm>, which this file does not include directly; it already relies on std::min at line 39 through the same transitive path, so this adds no new build risk — worth an explicit include if you touch the file again.
Patch record matches the [EXTERNAL] commit diff exactly modulo the subtree prefix; commit prefixes and license headers (MIT under external/triton/, Apache-2.0 WITH LLVM-exception for the new first-party .mlir) are correct. No rocMLIR back-port note needed — the only non-Triton paths are under mlir/test/.
Minor confidentiality note: the Test Result section links a Jenkins run on an internal CI host. Consider quoting the result rather than linking, since external readers cannot reach it.
CI status
All non-self checks pass. Code coverage is pending and the auto-review check is in progress; neither is a failure.
fe61ad7 to
3b85579
Compare
3b85579 to
af93b8f
Compare
|
@dhernandez0 @pabloantoniom The upstream PR was approved and merged by Alex triton-lang/triton@1725224a65ebc2dc7ca2ee1d84458344d93ee797. It is identical to the [EXTERNAL] commit here apart from the MIT header on the test, and the patch record now points at that merge commit |
pabloantoniom
left a comment
There was a problem hiding this comment.
Thanks for the patience in the review and for submitting the fix upstream!


Motivation
The weekly tuning stage aborts the compiler on gfx950. Three consecutive runs of PR #361 died the same way, always on gemm f16 m=384 k=3072 n=768 with the tuner emitted config
mPerBlock=1, nPerBlock=16, kPerBlock=2048, about a minute into the gemm stage. Because a failing chip aborts the rest of the matrix, this single config was enough to stop the whole weekly and hide every other chip's results.Technical Details
composePaddedLayoutForAsyncCopyCDNA4inthird_party/amd/lib/TritonAMDGPUTransforms/Utility.cppcomputeswarpSize / contigLaneswith integer division in two places. Once a row of the tile spans more than a warp of vectors, that iscontigLanes > warpSize, the quotient truncates to zero and two things break.requiredRowscollapses to zero, soxWayConflictsalways reports one and the "too few rows to stagger" path never triggers. And theuseBestWrapguard degenerates tononContigDim >= 0, which is always true, sowrapis forced to 16 even for a tile with a single row. Bases are then added for rows 1, 2, 4 and 8 that the tile does not have, the resulting linear layout broadcasts in the offset dimension, andPaddedSharedEncodingAttr::verifyrejects it. In an assertions build that aborts the compiler rather than falling back. The failing call chain isPipelinePasstoexpandLoopstolowerLoopstolowerLooptogetSharedEncIfAllUsersAreDotEnctocomposePaddedLayouttocomposePaddedLayoutForAsyncCopyCDNA4.The fix is the one suggested in the upstream review of triton-lang/triton#11890:
contigLanesis clamped to[1, warpSize]. A warp then counts as covering one row when a row is wider than a warp, sorequiredRowsand theuseBestWrapguard keep their original form and work again, and a row narrower than a vector can no longer makecontigLaneszero. The[EXTERNAL]commit is the upstream change plus its lit test, recorded astriton-patches/patch11890.patch; the downstream copy of the test only adds the MIT header this repo requires.Test Plan
mPerBlock1 to 64 andkPerBlock128 to 2048, compiled throughrocmlir-driver -cwith and without the change, comparing the generated code by hashing the lowered module, which embeds the HSACO.amd-pipeline-padded-layout-wide-row-gfx950.mlirand the new E2E testmlir/test/fusion/pr-e2e/rock-gemm-cdna4-padded-layout-wide-row.mlir.Test Result
triton-optwithout the change and passes with it. The E2E test runs the weekly's config plus a 2-row and a 4-row tile. All three abort the compiler without the change, and with it the test passes on the gfx950 CI node.Submission Checklist