Skip to content

feat(tma): add CTA-local G2S tile intrinsics - #1336

Merged
nihalpasham merged 20 commits into
NVIDIA:mainfrom
lucifer1004:feat/tma-g2s-cta-1238
Oct 19, 2026
Merged

nihalpasham merged 20 commits into
NVIDIA:mainfrom
lucifer1004:feat/tma-g2s-cta-1238

Conversation

@lucifer1004

@lucifer1004 lucifer1004 commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

What this adds

Two things that land together: SharedPtr<T>, a pointer into the issuing CTA's shared memory whose address space is part of its type, and cp_async_bulk_tensor_{1..5}d_g2s_cta, TMA tile loads into that memory through the PTX .shared::cta destination form (PTX 8.6, sm_90 and newer). The existing cp_async_bulk_tensor_Nd_g2s family and its cluster contract are unchanged.

A *mut T in device code is a generic pointer: once it crosses a helper boundary nothing says it points at this CTA's shared memory. SharedPtr<T> keeps that fact in the type and lowers to ptr addrspace(3) in parameters, returns, locals, struct fields, generics and closures, so the .shared::cta copy never has to guess, and ptxas on sm_120a no longer pays the runtime CTA check that made it drop setmaxnreg.

before (cluster form, sm_120a):
  cvta.to.shared::cluster.u64 ...
  cp.async.bulk.tensor.2d.shared::cluster.global.tile.mbarrier::complete_tx::bytes ...
  ptxas: C7506 setmaxnreg ignored, 24 registers, 8-byte stack
  SASS:  CALL.ABS.NOINC, UTMALDG.2D, no USETMAXREG

after (CTA form, sm_120a):
  cp.async.bulk.tensor.2d.shared::cta.global.tile.mbarrier::complete_tx::bytes [TILE], [tmap, {x, y}], [BAR]
  ptxas: no C7506, 168 registers, 0 stack
  SASS:  USETMAXREG.DEALLOC.CTAPOOL 0x28, UTMALDG.2D, USETMAXREG.TRY_ALLOC.CTAPOOL 0xe8, no CALL
static mut TILE: SharedArray<f32, 4096, 128> = SharedArray::UNINIT;
static mut BAR: Barrier = Barrier::UNINIT;

#[inline(never)]
unsafe fn load(dst: SharedPtr<u8>, tmap: &TmaDescriptor, x: i32, y: i32, bar: *mut Barrier) {
    unsafe { cp_async_bulk_tensor_2d_g2s_cta(dst, tmap, x, y, bar) } // dst is still addrspace(3) here
}

unsafe {
    let dst = SharedArray::shared_ptr(&raw mut TILE).cast::<u8>();
    load(dst, tensor_map, tile_x, tile_y, &raw mut BAR);
}

CTA-local TMA loads

SharedPtr<T>
unsafe SharedArray::shared_ptr(&raw mut S) the array's shared address, no conversion
DynamicSharedArray::<T>::shared_ptr() / shared_ptr_at(bytes) as get() / offset(bytes)
unsafe SharedPtr::from_raw(p) the explicit locality assertion, like __cvta_generic_to_shared or CuTe make_smem_ptr
add, offset, byte_add, cast pointer arithmetic that keeps the type
as_ptr() the generic *mut T, for loads, stores and raw-pointer APIs
addr_u32() the 32-bit .shared::cta address, for the _shared_u32 forms

What we fixed

  • On sm_120a, CUDA 13.3 and 13.4 ptxas lower every non-multicast .shared::cluster tensor load to a runtime CTA-id check with a syscall fallback. That call path makes ptxas ignore setmaxnreg (C7506), so a warp-specialized kernel runs with 24 registers instead of 168. Only a statically emitted .shared::cta form avoids it; sm_100a is native either way.
  • A *mut u8 from as_mut_ptr() or get() loses its shared-memory origin at the first helper boundary. SharedPtr keeps that origin in the type, so the proof the .shared::cta form needs does not depend on a caller promise.
  • A SharedPtr nested in another place, such as region.base after rustc inlines cast, was read as the address of an aggregate. The place walkers now drop the identity projection onto the newtype's field.
  • A kernel parameter that holds a shared or local pointer inside a struct or array compiled and applied cvta.shared to host-supplied bytes. The exporter now refuses it the way it refuses a bare one. Pre-existing with *mut Barrier, easier to reach with SharedPtr.
  • SharedArray::shared_ptr is unsafe, like as_raw_mut_ptr: the constructors establish the locality that addr_u32 relies on.

Contract

  • dst: SharedPtr<u8> points into the issuing CTA's shared memory by type. barrier: *mut Barrier must point into the issuing CTA's shared memory, as for every mbarrier operation.
  • A SharedPtr<T> comes from shared memory the CTA owns, or from a generic pointer through unsafe from_raw. For an address outside the shared window, addr_u32 yields an unspecified value.
  • Rejected at compile time: a SharedPtr kernel parameter, bare or inside a struct or array (the host has no shared address to pass), and a barrier passed straight from map_shared_rank_mut into the _cta form (a located error that names the cluster form).
  • Not rejected: SharedPtr::from_raw and pointer casts applied to a cluster pointer. Those are the caller's unsafe contract; the PTX ISA makes a .shared::cta copy into another CTA's memory undefined behavior.
  • The raw layer (cuda_intrinsics::tma::cp_async_bulk_tensor_Nd_g2s_cta, ABI i1034 to i1038) keeps *mut u8 and converts a generic pointer with cvta.to.shared; its safety text states CTA locality.
  • Unions and MaybeUninit<SharedPtr<T>> fail closed under the union storage guard; repr(packed) carriers follow the packed-carrier limits. On the modern libNVVM route (p3:32) a struct that mixes a SharedPtr with a narrower field is not yet supported in arrays or shared memory; see Caveats.
  • .shared::cta needs PTX 8.6; the module floor is raised when the typed intrinsic is present. The typed intrinsic needs LLVM 22 or newer; the pinned sysroot llc is LLVM 23.
Implementation
  • SharedSlot<T>(T) is a hidden repr(transparent) pointee marker; SharedPtr<T> { ptr: *mut SharedSlot<T> } is repr(transparent) with manual Clone and Copy. The importer types *mut SharedSlot<T> as a shared pointer in the pointee-keyed arm next to SharedArray and Barrier, and lowers SharedPtr<T> itself as a scalar newtype next to ThreadIndex; strip_shared_ptr_field_projections drops the Field(0) identity projection at the top of both place walkers.
  • The methods are plain #[inline(always)] Rust: casts between *mut SharedSlot<_> stay in addrspace(3), as_ptr is the 3 to 0 cast, from_raw the 0 to 3 cast, addr_u32 composes with cvta_generic_to_shared_u32.
  • Catalog: five [[tma.variant]] records with ABI entries i1034 to i1038 (appended, no renumbering), per-backend evidence profiles rust-llvm-23.1.3-aab11ee0-tma-cta and cuda-13.3-libnvvm-13.3.73-tma-cta, overlay shard schema 65 with a TMA_CTA_SHARD_SCHEMA gate; the two new shard fields are Option<String> with serde defaults and are required only when a shard lists g2s_cta variants.
  • Generator: recipes without the i16 multicast mask; imported properties ImmArg, IntrConvergent, ReadOnly<arg2>, WriteOnly<arg0>; PTX floor 8.6; dst: SharedPtr<u8> rendered for the device wrapper only; the raw-layer safety text carries the CTA-locality clause for the five records.
  • Importer: emit_tma_g2s_cta reuses the G2S emitter with a cta flag. Lowering: convert_g2s_cta beside the cluster lowering; LLVM NVPTX declares llvm.nvvm.cp.async.bulk.tensor.g2s.cta.tile.Nd(p3, p3, p0, i32 x N, i64, i1), libNVVM emits the .shared::cta inline PTX with ~{memory}, and an addrspace(7) operand is a located error. PTX-version detection recognizes the typed intrinsic (8.6 floor).
  • Exporter: the kernel-parameter check walks struct fields and array elements and names the offending field path.
  • Examples: tma_copy gains tma_copy_2d_cta_test and a generated-code check; shared_memory_helper gains the SharedPtr probe through a generic non-inlined helper, the two-field struct and returned-pointer regressions, and a code check that reads the unoptimized build; shared_ptr_api covers the remaining surface and runs through the libNVVM verifier in CI; error_kernel_shared_ptr_param is the nested-parameter negative.
  • Book: the SharedPtr section with its limits, the TMA chapter entry with the figure, the API quick reference, the supported-features note and the catalog stamp.

Verification

Checked at fbe27a694 on an RTX 5090 (sm_120a) with CUDA 13.4 and nightly-2026-10-11:

  • ✅ Tests of every touched crate (cuda-device, cuda-intrinsics-gen, cuda-intrinsics, cuda-oxide-codegen, mir-importer, mir-lower, dialect-nvvm, llvm-export, rustc-codegen-cuda), clippy and rustdoc with -D warnings, cargo oxide fmt --check, the 18 guards, the example lock check, cargo deny, the book with -W.
  • ✅ cuda-intrinsics-gen check, probe --all --skip-terminal --per-target, check-abi-history (1033 preserved, 1038 total), a second generate with no diff, the book stamp guard.
  • ✅ Evidence: the five CTA records' LLVM stages reproduce byte for byte from the pinned llc (LLVM 23.1.3) and ptxas 13.3 V13.3.73; the libNVVM file is the author's.
  • ✅ GPU: tma_copy on LLVM NVPTX and on libNVVM (--emit-nvvm-ir --arch sm_120), 4096 of 4096 values for the _cta kernel next to the unchanged kernels; shared_memory_helper on both routes, in the normal and the unoptimized build; shared_ptr_api on both routes; memcheck and synccheck 0 errors; the generated-code checks pass.
  • ✅ Ranks 1, 3, 4 and 5 executed at review time with real tensor maps through every SharedPtr provenance (static array, dynamic array, byte offset, from_raw, non-inlined helper): 1088 values on both backends, sanitizer clean; in tree they are covered by probes, cubin assembly and conversion tests.
  • ✅ The TMA G2S lowering makes ptxas ignore setmaxnreg via an extern compatibility call #1238 kernel (384 threads, setmaxnreg_dec::<40> / setmaxnreg_inc::<232>) at sm_120a with ptxas 13.4 and nvdisasm: the _cta form, direct and from an #[inline(never)] helper taking SharedPtr<u8>, gives 168 registers, 0 stack, USETMAXREG.DEALLOC/TRY_ALLOC, UTMALDG.2D, no CALL; the unchanged cluster form gives C7506, 24 registers, CALL.ABS.NOINC.
  • ✅ Negatives: a barrier from map_shared_rank_mut into _g2s_cta is a located error naming cp_async_bulk_tensor_2d_g2s; error_kernel_shared_ptr_param (Args { p: SharedPtr<f32>, n: u32 }) fails to compile with the located nested-path error; the llvm-export unit tests refuse { ptr addrspace(3), i32 } and [2 x ptr addrspace(3)] kernel parameters and keep accepting a struct of generic and global pointers.
  • ✅ PTX floor: tma_copy --arch sm_90a emits .version 8.6 and ptxas sm_90a assembles all three entries; the five probe PTX files assemble under ptxas 13.4; the pinned llc selects the typed intrinsic at +ptx86 and rejects it at +ptx85.
  • ✅ Baseline: the PTX of tma_copy_2d_test and tma_pipeline_test matches main's backend apart from symbol numbering; 8 unchanged shared-memory examples produce identical per-kernel PTX.

Caveats

  • Part of TMA G2S lowering makes ptxas ignore setmaxnreg via an extern compatibility call #1238, not a fix: the reproducer calls cp_async_bulk_tensor_2d_g2s, and the 39 in-tree cluster-form call sites keep .shared::cluster. Migration is tracked in Typed CTA-shared pointers so TMA G2S can use .shared::cta (SM12x setmaxnreg loss, #1238) #1337.
  • SharedPtr::from_raw and pointer casts can launder a map_shared_rank pointer into the typed form; the compiler rejects only an uncast addrspace(7) operand. A located importer error for that cast is a follow-up.
  • Modern libNVVM (p3:32): struct { p: SharedPtr<u8>, x: u32 } in a local array or a SharedArray traps with misaligned address because mir-lower sizes every pointer at 8 bytes when it picks a struct layout; the same happens with *mut Barrier on main. NVPTX is unaffected, and so are Region { SharedPtr, usize } and arrays of pointers. Tracked separately.
  • The shared_memory_helper code check reads the unoptimized build, the house mechanism for checks that need a real call boundary.
  • In-tree runtime coverage of the _cta family is 2D (tma_copy); ranks 1 and 3 to 5 ran in a scratch example at review time.
  • Tile mode only: no im2col, no L2 cache hint, no cta_group forms, matching the cluster family.
  • An llc older than LLVM 22 emits .extern .func declarations for the typed intrinsic without a diagnostic; the pinned sysroot llc is LLVM 23.

Supersedes #1341, whose commit lands here unchanged. Part of #1337.

lucifer1004 and others added 2 commits September 25, 2026 20:09
…e(3)

`SharedPtr<T>` is a raw pointer into the issuing CTA's shared memory
that carries its address space in its type. It wraps a
`*mut SharedSlot<T>`, which the importer types as an `addrspace(3)`
pointer, as it already does for pointers to `SharedArray` and
`Barrier`, and the importer lowers `SharedPtr` itself to that pointer.
Parameters, returns, locals, struct fields and generic code of type
`SharedPtr<T>` are therefore CTA-shared pointers by type, across calls
to non-inlined helpers, with no dataflow inference.

- Constructors: `SharedArray::shared_ptr(&raw mut S)` and
  `DynamicSharedArray::shared_ptr()` / `shared_ptr_at(bytes)` keep the
  allocation's shared address; `unsafe SharedPtr::from_raw` is the one
  explicit locality assertion.
- `add` / `offset` / `byte_add` / `cast` keep the type; `as_ptr` widens
  to a generic pointer; `addr_u32` gives the 32-bit `.shared::cta`
  address for the `_shared_u32` forms.
- The importer drops projections onto `SharedPtr`'s field, which are
  the identity for this scalar-lowered newtype, so a `SharedPtr` nested
  in another place is read as a pointer value.
- A kernel entry cannot take a `SharedPtr`: the exporter already
  rejects `addrspace(3)` kernel parameters.
- `shared_memory_helper` runs its probe a second time through a
  non-inlined generic helper that takes the `SharedPtr` in a struct;
  `verify-code-shape.sh` checks the helper's `ptr addrspace(3)`
  parameter and that no PTX converts a generic address to shared.

Refs NVIDIA#1337, NVIDIA#1238.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Zihua Wu <13583761+lucifer1004@users.noreply.github.com>
Add cp_async_bulk_tensor_{1..5}d_g2s_cta, the TMA tile load into the
issuing CTA's own shared memory
(cp.async.bulk.tensor.Nd.shared::cta.global...). Its destination is a
`SharedPtr<u8>`, a CTA-shared pointer by type (NVIDIA#1337), so the locality
the `.shared::cta` form needs comes from the type rather than from the
safety contract, including through helper functions. The raw ABI keeps
`*mut u8`, as `*mut Barrier` keeps `*mut u64`. The existing
cluster-shared G2S family is unchanged.

On SM12x, ptxas implements a non-multicast `.shared::cluster` tensor
load it cannot prove CTA-local with a runtime check and a syscall,
which makes it ignore `setmaxnreg` (NVIDIA#1238); this form avoids that.

- LLVM NVPTX lowers to the typed llvm.nvvm.cp.async.bulk.tensor.g2s.cta
  intrinsics; libNVVM uses the exact inline PTX, as the cluster forms do.
- A destination or barrier known to be cluster shared (addrspace 7)
  is a located compile error rather than a local offset.
- The PTX version detector also recognizes the typed intrinsics, so
  modules using them get PTX 8.6.
- Tests: mir-lower conversion tests for both backends and a negative
  addrspace(7) test, a detector test, the extended TMA admission
  ordering assertion, and a tma_copy kernel whose code-shape check
  requires the `.shared::cta` form with no address conversion.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Zihua Wu <13583761+lucifer1004@users.noreply.github.com>
@lucifer1004

Copy link
Copy Markdown
Contributor Author

Reworked per the plan in #1337. _g2s_cta now takes dst: SharedPtr<u8>, the typed CTA-shared pointer added in #1341, so locality comes from the type instead of an unsafe promise. The raw layer and ABI entries i1030–i1034 are unchanged. The branch is now #1341 plus one commit; review #1341 first. The description is updated.

@nihalpasham nihalpasham added the cuda-oxide SIMT programming model: rustc backend, cargo oxide, cuda-device, cuda-host, book label Oct 11, 2026
Replay the SharedPtr and CTA-local TMA G2S commits onto the monorepo
layout, nightly-2026-10-11 and pliron 0.20. Every conflicting generated,
probe, evidence and lock file takes main's copy; the catalog outputs are
regenerated in a following commit. The overlay keeps main's reduce LLVM
profile line and the two CTA profile lines, with the CTA LLVM profile
named after the evidence re-recorded under the pinned LLVM in that
commit. The book stamp paragraph keeps main's text until the
regeneration refreshes it. In mir-lower the `pliron::location::Located`
import goes away because `Operation::loc` is an inherent method in
pliron 0.20.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
…rd schema 65

The TMA overlay gained two required evidence-profile fields for the
CTA-local G2S variants, so a shard without them stopped parsing and every
fixture had to change. Follow the reduction-admission precedent instead:
the two fields are optional with a serde default, a shard that lists the
CTA-local variants must name both and must carry overlay shard schema 65,
and a shard without those variants still parses and expands to the cluster
family alone. The canonical-order check accepts either the full operation
list or the list without the CTA-local variants. The overlay shard schema
ceiling moves from 64 to 65 and tma.toml declares schema 65. Tests cover the
schema gate in both directions, the missing-profile error, the CTA-free
expansion and a partial CTA-local list.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
…h stale CTA comments

The raw ABI entries for the CTA-local G2S forms keep a generic destination
pointer that the lowering converts with cvta.to.shared, but their generated
safety text only asked for valid shared-memory objects. The renderer now
says that the destination and barrier must lie in the issuing CTA's own
shared memory and that a cluster-shared pointer from map_shared_rank would
yield a wrong local offset. The mir-lower doc comment for the CTA-local
lowering now describes the destination as shared by type with the barrier
as the caller's promise, and names the cast and from_raw gap. The importer
arity diagnostic names the _cta form when that form is being emitted.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
…nd regenerate

The CTA-local G2S evidence was recorded against the LLVM revision the
previous nightly shipped, which the catalog no longer admits. Replace it
with rust-llvm-23.1.3-aab11ee0-tma-cta.json, written from five candidate
probe runs of the pinned nightly-2026-10-11 sysroot llc at sm_90 +ptx86,
with CUDA 13.3 ptxas V13.3.73 as the terminal stage; every stage detail
cites the artifact sizes and SHA-256 digests of those runs. Regenerate the
catalog outputs on top of main's copies (catalog SHA-256 27a44de2: 581
operations, 555 generated, 1034 entries, tma 116) and refresh the book
stamp at both sites.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
…ed_memory_helper

Nothing in tree exercised a struct holding two SharedPtr fields passed by
value to a non-inlined helper, or a SharedPtr returned from a non-inlined
helper and used as a store target. A third kernel runs both shapes over 64
lanes with partner-lane overwrites, so the final values prove the stores
went through the scalarized parameters and the returned pointer. The
code-shape check now also requires both Pair fields to arrive as
ptr addrspace(3) parameters and select_slot to return ptr addrspace(3),
and the README describes the probe and the checks.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
…1038

Main assigned i1030 to i1033 to the bf16x2 to FP8x2 pack conversions after
this branch merged main, so the five cp_async_bulk_tensor_{1..5}d_g2s_cta
entries move to the next free ids above main's ledger tail. The overlay
shard, the generator recipes, the ordering test and the ledger carry the
new ids; the ledger stays ascending, with i1029 followed by i1034 until
the merge with current main brings in i1030 to i1033. The generated
outputs are regenerated in this same commit (catalog SHA-256 fa1e911b,
counts unchanged: 581 operations, 555 generated, 1034 entries, tma 116)
and the book stamp is refreshed at both sites.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
Second merge with main, which gained 15 commits since the first one.
Every conflicting generated, probe, evidence, catalog, reference and
lock file takes main's copy; the catalog outputs are regenerated in the
following commit. The ABI ledger keeps main's new entries i1030 to
i1033 ahead of the CTA-local entries i1034 to i1038. The overlay shard
schema is 65 on both sides. The generator test totals become 67 shards
and 1038 entries. The shared-memory book page keeps main's dynamic-pool
alignment paragraph ahead of the SharedPtr section, and the dialect
page keeps main's catalog stamp until the regeneration refreshes it.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
The merged overlay holds main's bf16x2 to FP8 pack admission (i1030 to
i1033) next to the CTA-local TMA entries (i1034 to i1038), so the
catalog hash and every generated, probe and reference file change.
Generated by `cargo run -p cuda-intrinsics-gen -- generate` with no
hand edits.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
…erge

The merged catalog hashes to 7e6b4b4b and resolves 1038 entries into 559 generated operations, 585 in all with the 26 hand-written ones. The tma and packed rows were already current.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
The constructor is what makes a SharedPtr's locality claim true, and the
safe addr_u32 relies on it. It now carries the same Safety section as
as_raw_mut_ptr: a static mut SharedArray of the current kernel, obtained
with &raw mut. DynamicSharedArray::shared_ptr and shared_ptr_at stay
safe, as get and offset are. The doc examples wrap the call in unsafe.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
…pointers inside aggregates

The kernel-parameter check downcast only the top-level type, so a
struct { p: SharedPtr<f32>, n: u32 } parameter compiled, declared a
16-byte .param and applied cvta.shared.u64 to host bytes; a *mut Barrier
field had the same hole. The check now looks through struct fields and
array elements and names the field path it found, with a message
distinct from the bare form so a fixture can pin the nested case.

Unit tests cover a struct, an array, a pointer nested below an array
element, and the accepted shapes (a struct of generic and global
pointers on a kernel, the shared-holding struct on a device function).
The new error_kernel_shared_ptr_param fixture pins the nested diagnostic
in the smoketest error lane, with its STATUS.md row and verdict case.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
The module-wide cvta.to.shared search also passed on main's build of
this example. The script now also requires the .ll call site to pass a
ptr addrspace(3), a PTX .func for shared_ptr_probe that the kernel calls
once with mbarrier.init.shared inside its body, and no cvta.to.shared or
isspacep anywhere; when the .func is missing it says to build with
CUDA_OXIDE_NO_OPT=1. The example joins NO_OPT_SHAPE_EXAMPLES so the
smoketest reads the unoptimized artifacts, and the README says that the
no-feature build runs the typed probe and that the PTX half reads the
unoptimized build.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
…oundaries

Eleven kernels move a SharedPtr through the boundaries the review's
scratch batteries covered: a non-inlined helper returning one, &Region<T>
and &mut SharedPtr<T>, a closure through a generic apply, [SharedPtr<T>; 2]
by value, Option<SharedPtr<u32>>, a SharedArray of SharedPtrs in shared
memory, transmute to usize and back, a from_raw round trip with a
negative offset, addr_u32 against cvta_generic_to_shared_u32, a struct
pointee with a cast to its first field, and f64 and u16 byte views. The
host checks every value and prints one SUCCESS line.

Listed in NVVM_VERIFY_EXAMPLES so the compile-only lane also runs it
through libNVVM. Structs that mix a SharedPtr with a narrower field stay
out: on the p3:32 route they are not yet supported in arrays or shared
memory.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
The snippet imports thread and kernel, lives in a kernel, uses the
dynamic pool pointer it declares, and wraps the unsafe constructor. A
paragraph after the table lists the limits: no SharedPtr kernel
parameter, bare or inside a struct or array; unions and MaybeUninit fail
closed under the union storage rules; repr(packed) carriers follow the
packed limits; and on the libNVVM route a struct that mixes a SharedPtr
with a narrower field is not yet supported in arrays or shared memory,
a gap that predates SharedPtr. The appendix carries the same note next
to the union limits.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
The strip exists because SharedPtr's scalar is itself a pointer, which
the iterative place walker takes as an address to load from. An integer
scalar newtype such as ThreadIndex already has identity extract_field
arms in dialect-mir and mir-lower, so it needs none. The follow-up is to
have the walker track address versus value and then drop the strip.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
Signed-off-by: nihalpasham <nihalp@nvidia.com>
A one-page figure for the book and the pull request, in the style of the
tile-libraries direct-linkage figure.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
SharedArray::shared_ptr is an unsafe constructor now, and the copy itself
is unsafe, so the fragment shows the block and its safety argument like
the shared-memory chapter's snippet does.

Signed-off-by: nihalpasham <nihalp@nvidia.com>
@nihalpasham
nihalpasham self-requested a review as a code owner October 19, 2026 16:09
@copy-pr-bot

copy-pr-bot Bot commented Oct 19, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@nihalpasham nihalpasham added enhancement New feature or request perf Performance of generated code or of the compiler itself intrinsics Device intrinsics and libdevice math mappings labels Oct 19, 2026
@nihalpasham nihalpasham added codegen Device code-generation pipeline (Rust MIR to IR to PTX) IR-lowering Lowering between dialects (dialect-mir to LLVM dialect) device-apis User-facing device-side and kernel-authoring APIs (cuda-device, cuda-macros) cuda-feature A CUDA hardware/toolkit feature (TMA, tcgen05, WGMMA) examples Example kernels and host harnesses under crates/rustc-codegen-cuda/examples labels Oct 19, 2026
@nihalpasham

Copy link
Copy Markdown
Collaborator

/ok to test fbe27a6

@nihalpasham

Copy link
Copy Markdown
Collaborator

Thanks, this is the explicit local API I asked for in #1249, with the cluster contract left alone. This PR carries the SharedPtr commit from #1341, so both land here. I replayed both commits onto current main and layered on what the landing needed:

  • Re-recorded the CTA LLVM evidence under the pinned LLVM (rust-llvm-23.1.3-aab11ee0) and regenerated; the five records sit at ABI ids i1034 to i1038 because feat(intrinsics): admit bf16x2 to FP8x2 pack conversions #1354 landed first.
  • Gated the two new shard fields behind a schema bump, as feat(intrinsics): add TMA tensor reduction intrinsics #770 did for the reduction forms, so older shards still parse.
  • Stated CTA locality in the raw-layer safety text, which still takes a generic *mut u8 and converts it with cvta.to.shared.
  • Made SharedArray::shared_ptr unsafe, like as_raw_mut_ptr: the constructors are what make the type's locality claim true.
  • The exporter now refuses a kernel parameter that carries a shared or local pointer inside a struct or array, not only a bare one. struct { p: SharedPtr<f32>, n: u32 } compiled and applied cvta.shared to host bytes. New fixture and unit tests.
  • Added shared_ptr_api, the generic-helper regressions from fix(tma): select CTA-local G2S on SM120/SM121 #1249, plus the two-field struct and returned-SharedPtr shapes in shared_memory_helper, whose code check now reads the unoptimized build so the call boundary is real.
  • Book: the limits paragraph, two stale comments from the pre-SharedPtr design, and a one-page figure.

On the 5090, tma_copy, shared_memory_helper and shared_ptr_api pass on both backends with memcheck and synccheck clean, and the #1238 kernel keeps setmaxnreg with the _cta form: 168 registers, UTMALDG.2D, no CALL. The cluster path is unchanged in PTX.

At fbe27a694, the full local checks and every CI check passed, apart from the CodeQL analysis, still queued behind today's GitHub Actions incident.

This is part of #1238; the reproducer path and the in-tree cluster-form callers stay on #1337.

@nihalpasham
nihalpasham merged commit 8bb24a4 into NVIDIA:main Oct 19, 2026
64 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codegen Device code-generation pipeline (Rust MIR to IR to PTX) cuda-feature A CUDA hardware/toolkit feature (TMA, tcgen05, WGMMA) cuda-oxide SIMT programming model: rustc backend, cargo oxide, cuda-device, cuda-host, book device-apis User-facing device-side and kernel-authoring APIs (cuda-device, cuda-macros) enhancement New feature or request examples Example kernels and host harnesses under crates/rustc-codegen-cuda/examples intrinsics Device intrinsics and libdevice math mappings IR-lowering Lowering between dialects (dialect-mir to LLVM dialect) perf Performance of generated code or of the compiler itself

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants