Repository navigation
Tile libraries: call Rust device functions from Tile kernels - #1542
Closed
nihalpasham wants to merge 3 commits into
Closed
nihalpasham wants to merge 3 commits into
nihalpasham wants to merge 3 commits into
Conversation
Tile IR 13.5 adds the public preview `simt` feature: a Tile program can call a native SIMT function from a tile library. This teaches cutile-ir the content such a library is made of and how a caller reaches it: - the ops `preview$func extern`, `preview$extern_impl` and `preview$call`, the fragment type and the symbolic layout attributes (fragmap, mem_layout, synchronization, access, scratch), with textual printing, decoding and structural verification; - the 13.5 header tag and function table form, selected automatically when a module carries preview content; everything else still writes 13.4, and negotiation with tileiras still stops there; - a typed `tilelib` API (`ExternFunc`, `ExternImpl`, `interface_module`, `implementation_module`, `verify_library`, `preview_call`) that builds the two bytecode halves of a library without touching op payloads; - `toolchain::list_bytecode_versions` and public names for the environment variables the toolchain lookup reads. Checked against the reference implementation: the fixture modules print like the upstream `.mlir` test inputs, the decoder round trips every new op, and the `preview$call` encoding is byte-identical to what cuTile Python's `foreign_call` emits for the same program. The compatibility table in the book is regenerated for the new column. Signed-off-by: nihalpasham <nihalp@nvidia.com>
…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>
…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 cutile-ir's typed API, writes the Tile IR 13.5 interface and implementation bytecode plus a readable `.tilelib.mlir`, and asks `tileiras --preview-create-tile-lib` for the `.tilelib` when the installed assembler lists bytecode 13.5. 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`). Its host program proves the ABI on the installed toolkit: it generates a CUDA C++ caller from the descriptions, compiles it to LTOIR with nvcc, links both halves with nvJitLink and checks the numbers on the GPU. `python/call_from_cutile.py` is the cuTile Python caller (`foreign_call`), with a dry run that stops at the bytecode. Also: the smoketest `tilelib` lane, the book chapter on tile libraries, CI path filters for `cutile-rs/cutile-ir`, and cargo-oxide's path dependency on that crate. Signed-off-by: nihalpasham <nihalp@nvidia.com>
nihalpasham
requested review from
binarybana,
cryos,
elibol,
kkraus14 and
rparolin
as code owners
October 18, 2026 13:18
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.
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
cutile-irwrites the Tile IR 13.5 and 13.6 preview content:preview$func extern,preview$extern_impl,preview$call, fragment types and the symbolic layout attributes, behind a typedtilelibAPI, with a decoder and a structural verifier. The default version for ordinary kernels stays 13.4.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, builds 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
d1b988b2:preview$callbytes equal to cuTile Python's), clippy, rustdoc.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).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.cargo-oxidenow depends oncutile-rs/cutile-irby path, so the SIMT CI lanes also watch that directory.