Repository navigation
Tile libraries: call Rust device functions from Tile kernels - #1545
Merged
Merged
Conversation
nihalpasham
requested review from
binarybana,
elibol and
kkraus14
as code owners
October 18, 2026 14:34
nihalpasham
force-pushed
the
feat/tile-simt-interop
branch
from
October 18, 2026 14:39
b1d6b1f to
1cd610b
Compare
…ile kernels `#[tile_export(shape = N, ...)]` marks a device function as an entry of a cuTile tile library. The attribute leaves the function as it is and generates two items beside it: a `#[device] extern "C"` wrapper on the native SIMT ABI the Tile compiler calls (`in` scalars by value, `&T`, `&mut T`, `&[T; N]` and `&mut [T; N]` as pointers, a scalar return as a trailing `out` pointer), and a host-only metadata function whose body is the export's JSON description. - `oxide-tile-export` (new crate): the description vocabulary shared by the macro, the backend and `cargo oxide tilelib`, with the rules a library entry must satisfy (one dimension, one footprint for every parameter, one contiguous run of written parameters, whole warps for `sync = "warp"`). - `reserved-oxide-symbols`: the `cuda_oxide_tile_export_246e25db_` prefix of the metadata functions. - `rustc-codegen-cuda`: the collector reads each description out of the metadata function's MIR, roots the wrapper even when the crate has kernels, rejects duplicate names and symbols and device-side calls of the metadata function, and writes `<crate>.tileexports.json` next to the device artifact. - trybuild tests for the accepted forms and every rejection; the example lockfiles pick up the new dependency of cuda-macros. Signed-off-by: nihalpasham <nihalp@nvidia.com>
A tile library lets a Tile kernel call a SIMT function. cuda-oxide is the SIMT provider: it ships the code as LTOIR and describes it twice, as the declaration a Tile kernel calls and as the native symbol with the fragment each parameter receives. This crate writes those two descriptions as Tile IR bytecode and nothing else in the format: header, function table with bodiless `preview$func extern` and `preview$extern_impl` entries, type and string tables, and the one-entry debug table. - A small model (`Declaration`, `Implementation`, tiles, fragments, layouts, the synchronization, arch and frontendABI clauses) with a verifier for the rules the Tile compiler applies when the halves meet. - `interface_bytecode` and `implementation_bytecode` take the version the consuming assembler calls current; preview content is readable at no other version, and anything below 13.5 is an error. - A readable textual form of both modules. Every encoding was derived from the Tile IR compiler sources and checked against the CUDA 13.6 assembler: `tileiras --preview-create-tile-lib` packs this crate's output into a library a Tile C++ kernel then calls. Signed-off-by: nihalpasham <nihalp@nvidia.com>
nihalpasham
force-pushed
the
feat/tile-simt-interop
branch
from
October 18, 2026 15:32
1cd610b to
81452f9
Compare
…mple `cargo oxide tilelib <crate> --arch sm_XX` packages a crate's `#[tile_export]` functions as a cuTile tile library. It runs emit-ltoir, checks that the NVVM IR defines every implementation symbol with the parameter list the native SIMT ABI predicts, maps the descriptions to the oxide-tilebc model, writes the interface and implementation bytecode plus a readable `.tilelib.mlir`, and asks `tileiras --preview-create-tile-lib` for the `.tilelib`. An assembler reads preview content only at the version it calls current, so the descriptions are written at the newest version the installed tileiras lists (13.5 when none can read them yet). An older assembler stops after the descriptions with exit 2, or exit 0 with `--library-optional`; the summary ends with a "written to" or "skipped" line that scripts read. The `tilelib_relu` example is a three-export library (`relu`, `scale_in_place`, `warp_sum`) with three consumers: a host program that proves the ABI on the installed toolkit (a CUDA C++ caller generated from the descriptions, linked with nvJitLink, checked on the GPU), a Tile C++ kernel in `cpp/tile_caller.cu` built with nvcc's `--enable-tile` and `--tile-preview simt`, and a cuTile Python kernel in `python/call_from_cutile.py` with a dry run that stops at the bytecode. Also: the smoketest `tilelib` lane and the book chapter on tile libraries. Signed-off-by: nihalpasham <nihalp@nvidia.com>
nihalpasham
force-pushed
the
feat/tile-simt-interop
branch
from
October 18, 2026 15:37
81452f9 to
a7c465e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
A Rust device function can now be called from inside a Tile kernel.
#[tile_export]marks the function, andcargo oxide tilelibpackages the crate as a.tilelib, the static tile library format tileiras links with-l.cargo oxide tilelib tilelib_relu --arch sm_120 # -> tilelib_relu.tilelibcuda-oxide is the SIMT provider: it ships the code (LTOIR from the existing pipeline) and two small descriptions (the interface and the implementation, as Tile IR bytecode). tileiras does the matching, marshalling and linking. The Tile side only emits the call. Everything lives under
cuda-oxide/;cutile-rsis untouched.The contract
inscalars are passed by value,&T,&mut Tand fixed arrays as pointers, and a scalar return value becomes a trailingoutpointer.#[tile_export]generates that wrapper next to the function.sync = "warp"means 32 lanes call the function together, so warp shuffles are legal inside it.Implementation
oxide-tilebcis a new crate that writes the two descriptions as Tile IR bytecode (preview$func externandpreview$extern_impl, with the fragment types and layouts they carry). It has a typed model, a structural verifier with the Tile compiler's rules, and a textual printer in the upstream form for the--dumpoutput. It writes nothing else of the format; ordinary kernels are not touched.oxide-tile-exportis the shared description vocabulary and its rules (one dimension, one footprint per export, written parameters as one contiguous run, whole warps for warp sync).#[tile_export]generates theextern "C"wrapper plus a host-only metadata function whose body is the JSON description; the backend reads it from MIR, roots the wrapper, and writes<crate>.tileexports.jsonbeside the device artifact.cargo oxide tilelibruns emit-ltoir, checks that the NVVM IR defines every symbol with the parameters the ABI predicts, writes both bytecode halves, and callstileiras --preview-create-tile-lib. On an older assembler it stops after the descriptions with exit 2, or exit 0 with--library-optional, which is how the smoketest's newtileliblane runs it.tilelib_reluexample has three consumers: a host program that proves the ABI on CUDA 13.4 (a CUDA C++ caller generated from the descriptions, linked with nvJitLink), a Tile C++ kernel (cpp/tile_caller.cu), and a cuTile Python kernel (python/call_from_cutile.py).Verification
Checked at
a7c465e9d:cargo oxide run tilelib_reluverifies all three exports through the native ABI on CUDA 13.4.cargo oxide tilelibbuildstilelib_relu.tilelib, and the Tile C++ kernel calls all three exports through it (3 of 3, bit for bit). The decoded descriptions equal the accepted reference bytecode.preview$calltorelu.Caveats
.tilelibitself needs a CUDA 13.5 or newer tileiras; on 13.4 the command writes the descriptions and the LTOIR and says so.f16but notbf16, concrete shapes only. Linkage providers (implementations compiled on demand) are not part of this change.