Skip to content

shim BD: derive the granule from dtype, and share one run-split helper - #211

Draft
atassis wants to merge 2 commits into
amd:develfrom
atassis:pr/share-shim-bd-run-split
Draft

atassis wants to merge 2 commits into
amd:develfrom
atassis:pr/share-shim-bd-run-split

Conversation

@atassis

@atassis atassis commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

gemv and repeat both split a contiguous run into shim BD wrap dimensions, each hand-rolling the
same invariant. gemv also carried a FIXME asking for the bounds to come from the target model, and
a granule constant that was bf16-only:

GRAN_ELEMS = 2  # 4-byte shim granularity / 2-byte bf16 element

That is wrong for every other dtype it accepts. The shim's address-generation granularity is 32 bits,
so the granule is 4 elements for int8 and 1 for f32 -- an element-unit bound derived from 2 is 2x too
strict for int8 and 2x too loose for f32.

Added

  • iron/common/shim_bd.py with one split_run helper, and its tests.
  • _shim_gran_elems(dtype), deriving the granule from the memref's element type, mirroring what verifyStridesWraps computes from getAddressGenGranularity(). It asserts the element width divides the granularity rather than silently truncating.

Changed

  • gemv and repeat both use the shared helper.
  • The bound comment now records that these are the ShimNOC numbers specifically; MemTile and CoreTile have different wrap/step widths, so reusing them elsewhere would silently under- or over-shoot.

Removed

  • gemv's local split_run, MAX_WRAP/GRAN_ELEMS/MAX_STRIDE, and the FIXME.

The bounds stay hard-coded, with a comment saying why: getDmaBdWrapBits/getDmaBdStepBits have no
Python binding, and getAddressGenGranularity has a CAPI entry but is not bound into
aie.dialects.aie.AIETargetModel.

Verified on 27cf75d: pytest iron/common/test_shim_bd.py iron/operators/gemv/test.py -> 60 passed
for the shim-BD and granule selections, covering bf16/int8/f32 granules and the split invariant.
black --check clean. Pure arithmetic; no device. The gemv/repeat device paths are unchanged in shape
but not re-run here.

PR Merge Checklist

  1. The PR is rebased on the latest devel commit and pointing to devel.
  2. Your PR has been reviewed and approved.
  3. All checks are passing.

GRAN_ELEMS was hard-coded to 2 (4-byte shim granularity / 2-byte bf16)
regardless of what was actually being transferred -- unreachable today since
dtype_in/dtype_out are hard-coded bf16 here, but silently wrong for any
future non-bf16 variant of this design.

Derive the granule from dtype_in/dtype_out instead, and rename
MAX_WRAP/MAX_STRIDE to SHIM_MAX_WRAP/SHIM_MAX_STRIDE: they are the
ShimNOC-specific verifyStridesWraps bounds, not MemTile's or CoreTile's,
both of which differ. Hoists split_run to module scope so it's testable
in isolation.

test_shim_gran_elems_matches_dtype fails (ImportError) without this and
pins a concrete misaligned split at the old gran=2.
gemv and repeat each carried their own search for the same ShimNOC BD invariant:
factor a contiguous run into (count, length) with both dims inside the 10-bit wrap
field and the innermost length a whole number of 32-bit words, length maximal.
Two implementations of one hardware constraint is the hazard -- amd#161 had to rebuild
the invariant for repeat because gemv learned it somewhere unreachable.

Moves SHIM_MAX_WRAP / SHIM_MAX_STRIDE / SHIM_ADDR_GRAN_BITS, shim_gran_elems() and
split_run() into iron/common/shim_bd.py and points both operators at it. split_run
keeps returning None rather than raising, because the callers legitimately disagree
about it: gemv has a slower legal path and falls back, repeat does not and raises.

Behaviour-preserving for repeat, and checked rather than asserted: repeat searched
divisors upward, split_run searches the length downward, and the two agree on all
17997 (cols, granule) pairs over cols<3000 x granule in {1,2,4}, no-split cases
included. That differential is kept as a test, alongside one that the returned split
is actually emittable and one that the inner run is maximal -- a short innermost dim
is legal but slow, so a regression would otherwise pass silently.

shim_gran_elems also stops asserting on elements at least as wide as the granule
(f64 returned max(1, 4//8) = 1 from repeat before; the gemv version would have
tripped its assert). repeat takes arbitrary dtypes, gemv does not.

Tests: 40/40 of amd#161 repeat, 5/5 gemv unit, 55 new. No device.

@andrej andrej left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be an upstream change to MLIR-AIE instead, where we can access/expose the required fields from the TargetModel? And make IRON a user of it only.

@atassis

atassis commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

@andrej really the job was done in Xilinx/mlir-aie#3728. So after that lands- I can wire it into the IRON later

@andrej

andrej commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

That's even better. Please ping here when upstream lands, and we can update this PR to make use of those changes. I'll hold off until merging until then and mark it draft until then.

@andrej
andrej marked this pull request as draft September 18, 2026 18:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants