NVIDIA公式のCUDA RustによるGPUネイティブプログラミング
目次
NVIDIAは2026年9月8日、Rustから直接GPUカーネルを記述・コンパイルできる公式ツールチェーン「CUDA Rust」を発表した。
同時に開催されたRustConf 2026において、NVIDIAがRust Foundationの最上位枠「Platinum Member」へ加盟したことも発表された。
NVIDIAはこれまでも、Linuxディストリビューション向けのNovaドライバや推論基盤NVIDIA Dynamoのコア実装においてRustの採用を進めてきた。
今回の発表では、GPU上で実行する計算カーネルそのものをRustネイティブで記述する環境を公式に整備し、C++やPythonに並ぶ第一級の言語としてCUDAエコシステムへ組み込む方針を示している。
提供されるツールチェーンは、低レベルなスレッド制御を行う「cuda-oxide」と、データブロック単位で安全に並列処理を記述する「cutile-rs」の2つのトラックで構成されている。
従来のサードパーティ製クレートとの違い、2つのトラックのアーキテクチャ、メモリ安全性の設計について整理した。
従来のRust GPUエコシステムとの違い
従来のRust環境からNVIDIA製GPUを利用する場合、主に3つの手法が使われてきた。
1つ目は、cudarc をはじめとするホスト側APIラッパーを利用する構成。
GPUカーネル自体はCUDA C++で書き、NVIDIA公式コンパイラの nvcc でPTXまたはcubinバイナリへ事前にコンパイルしておく。
RustプログラムはDriver APIを介してそのバイナリをロードし、ポインタを渡してカーネルを起動する。
この方式では、ホスト側のメモリ管理はRustで書けるものの、カーネルコードの記述にはC++が必要になり、開発パイプラインが2言語に分断される。
2つ目は、rust-cuda などのコミュニティ主導による実験的コンパイラを利用する構成。
LLVMのNVPTXバックエンドを利用してRustからPTXコードを出力する試みだったが、nightly Rustの内部API変更や最新GPUアーキテクチャへの追従に多大な労力を要し、実用環境での継続的な保守が困難だった。
3つ目は、C++で書いたCUDAコードを extern "C" 経由でRustから呼び出すFFIバインディング。
build.rs 内で cc クレートやCMakeを呼び出してビルドを自動化するが、型情報の不一致やホスト・デバイス間のメモリ境界における安全性が保証されない。
flowchart TD
A["従来の構成: CUDA C++ (.cu)"] -->|nvccで事前コンパイル| B["PTX / cubin バイナリ"]
C["Rustホストコード (.rs)"] -->|Driver API経由でロード| B
B --> D["GPU実行(2言語に分断)"]
E["CUDA Rust: 単一のRustコード (.rs)"] -->|cuda-oxide / cutile-rs| F["直接PTX出力 / JIT実行"]
F --> G["GPU実行(Rustで完結)"]
CUDA Rustは、NVIDIA公式のサポートによってこの分断を解消する。
C++ラッパーや外部の nvcc ビルド工程を挟まず、Rustのコードから直接PTXコードを出力する。
ホストコードとデバイスカーネルを同一のクレート内で完結させるシングルソース体験を提供し、Cargoのビルドワークフローに直接統合できる。
スレッド単位を制御するSIMTトラックのcuda-oxide
cuda-oxide は、従来のCUDA C++と同じSIMT(Single Instruction, Multiple Threads)モデルを採用した低レベルトラック。
各GPUスレッドの振る舞いを直接記述し、共有メモリやスレッド同期を明示的に制御する用途に向いている。
コンパイルパイプラインとアーキテクチャ
cuda-oxide は、Rustコンパイラ(rustc)のカスタムコードジェネレータ(codegen backend)として動作する。
コンパイル処理は次の経路を通過してPTXを出力する。
rustcがRustコードを解析し、MIR(Mid-level Intermediate Representation)を生成する。cuda-oxideがカーネル関数(#[kernel])のMIRをインターセプトする。- MLIRベースの独自IRフレームワーク「Pliron」を経由してGPU向けの中間表現に変換する。
- LLVMのNVPTXバックエンドを通じてネイティブなPTXコードを直接生成する。
外部のC++コンパイラを介さずMIRから直接PTXを出力するため、Rustのジェネリクス、トレイト、クロージャなどの言語機能をカーネル内部でそのまま展開できる。
カーネルコードの記法
cuda-oxide では、モジュールに #[cuda_module] 属性を付与し、カーネル関数に #[kernel] を指定して記述する。
use cuda_core::simt::LaunchConfig;
use cuda_device::{cuda_module, kernel};
#[cuda_module]
mod kernels {
use super::*;
#[kernel]
pub fn vector_add<T: Copy + std::ops::Add<Output = T>>(
a: &[T],
b: &[T],
c: &mut [T],
) {
let idx = cuda_core::thread::index();
if idx < c.len() {
c[idx] = a[idx] + b[idx];
}
}
}
スレッドインデックスの取得には cuda_core::thread::index() を使用し、配列の境界判定や要素加算を標準的なRust構文で記述できる。
ホスト側コードと同じファイル内にカーネル定義を同居させることが可能で、型パラメータ T はコンパイル時に具体的な型へ単相化される。
開発ステータスと要件
cuda-oxide は2026年9月時点でEarly alphaの段階にある。
rustc の内部データ構造に直接介入するcodegen backendの構造上、Pinned nightly Rustツールチェーンおよび専用ビルドされたLLVM環境を要求する。
安定版のRustツールチェーンにはまだ統合されていないため、言語仕様の変更や内部APIの更新に伴う破壊的変更が発生しやすい状態にとどまる。
データチャンクを扱うTileトラックのcutile-rs
cutile-rs は、スレッド単位ではなくデータブロック(タイル)単位で並列処理を記述するTileプログラミングモデルを採用したハイレベルトラックに当たる。
GPUの低レベルなスレッド管理やハードウェア固有のレイアウト計算を抽象化し、メモリ安全性を言語仕様レベルで保証する設計を持つ。
テンソル分割による所有権モデルの拡張
従来のCUDAでは、各スレッドが共有ポインタを通じて配列へアクセスするため、別スレッドが同じメモリ領域へ同時に書き込むデータ競合が発生しやすかった。
cutile-rs は、Rustの借用チェッカー(Borrow Checker)をGPUカーネルの実行境界まで拡張している。
ホスト側でテンソルを確保する際、.partition() メソッドを用いてテンソルを互いに重複しないチャンク(Disjointなサブテンソル)へ分割する。
カーネル関数へ渡される可変参照 &mut Tensor は、型システム上で排他アクセスが保証された独立ブロックとして扱われる。
これにより、複数のGPUワーカーが同一領域を同時に書き換える競合状態をコンパイル時に排除し、unsafe ブロックを使わずに安全なカーネルを記述できる。
カーネルコードとホスト側の連携
cutile-rs はマクロとCUDA Tile IRによるJITコンパイル方式を採用している。
use cutile::api;
use cutile::prelude::*;
#[cutile::module]
mod kernels {
use super::*;
#[cutile::entry()]
fn vector_add<const B: i32>(
z: &mut Tensor<f32, {[B]}>,
x: &Tensor<f32, {[-1]}>,
y: &Tensor<f32, {[-1]}>,
) {
let tx = x.load_like(z);
let ty = y.load_like(z);
z.store(tx + ty);
}
}
async fn run() -> Result<(), Box<dyn std::error::Error>> {
let size = 1024;
let x = api::ones::<f32>(&[size]).await;
let y = api::ones::<f32>(&[size]).await;
// 出力先テンソルを128要素ごとの独立チャンクへ分割
let z = api::zeros::<f32>(&[size]).partition([128]);
// カーネル起動と同期
let (_z, _x, _y) = kernels::vector_add(z, x, y).sync()?;
Ok(())
}
カーネル引数には定数ジェネリクス(const B: i32)を用いてタイルサイズを渡す。
load_like や store などの高レベルAPIを通じて、共有メモリへのキャッシュ読み込みやレジスタ転送が自動的にスケジューリングされる。
ホスト側のAPIは async/await 構文を標準でサポートしており、CUDAストリームの非同期キューイングやグラフ再生(CUDA Graph Replay)を非同期タスクとして扱える。
動作環境と採用実績
cutile-rs は、Stable Rust 1.89以上とCUDA 13.3の組み合わせで動作する。
コンパイラ本体のフォークやカスタムLLVMを必要とせず、通常のCargo環境にクレートを追加するだけで利用できる。
すでに実用段階のワークロードにも導入されており、Hugging Faceの分散推論エンジン「Grout」や、Rust製のLLM推論フレームワーク「mistral.rs」においてGEMM(一般行列積)やアテンション演算のバックエンドとして組み込まれている。
ベンチマークではベンダー最適化ライブラリの cuBLAS に匹敵するスループットを達成している。
2つのトラックの機能と仕様の比較
cuda-oxide と cutile-rs は、開発目的や抽象度のレイヤーが異なる。
| 項目 | cuda-oxide(SIMT Track) | cutile-rs(Tile Track) |
|---|---|---|
| プログラミング単位 | スレッド(Thread) | タイル(Tensor Block) |
| 抽象度 | 低レベル(CUDA C++相当) | 高レベル(DSL / タイル演算) |
| メモリ安全性 | DisjointSlice とローンチ規約による管理 | 所有権分割によるコンパイル時競合排除 |
unsafe の要否 | 低レベル制御時に一部必要 | 不要(完全なSafe Rustを志向) |
| コンパイル方式 | rustc codegen backend による直接PTX出力 | マクロ展開とCUDA Tile IRによるJITコンパイル |
| Rustツールチェーン | Pinned nightly + カスタムLLVM | Stable Rust(1.89以上) |
| 必要CUDA環境 | 開発環境に準拠 | CUDA 13.3以上 |
| 開発ステータス | Early alpha(実験段階) | 早期採用段階(推論エンジン等で実績あり) |
| 主な用途 | 細かなスレッド制御、カスタム命令最適化 | ディープラーニング演算、GEMM、テンソル処理 |
柔軟なハードウェア制御や独自のアセンブリ命令操作を求める場合は cuda-oxide が選択肢となり、行列演算やメモリ安全性を重視する高速推論パイプラインには cutile-rs が適している。
型システムによるGPUカーネルの安全性保証
従来のCUDA C++開発では、ポインタ操作やスレッド同期に起因するバグが実行時まで発覚しにくい問題があった。
CUDA Rustは、Rust言語の型システムと静的解析をGPUプログラミングへ持ち込むことで、これらの問題をコンパイル段階で検出する。
主な安全性のアプローチは次の3点。
- エイリアシングの防止: C++では同一バッファに対するポインタを複数スレッドへ渡した際に、意図しない重複書き込みが発生しやすかった。CUDA Rustでは、
DisjointSlice型やテンソルの排他分割により、各ワーカーがアクセスできるメモリスライスが重ならないことを型システム上で強制する。 - データ競合の静的排除: Rustの「排他可変借用(
&mutは同時に1箇所のみ)」規則がデバイス側コードにも適用される。読み取り専用参照(&)は複数スレッド間で共有可能だが、書き込みを行う参照は単一のタイルに制限されるため、同時書き込みによる破壊が起きない。 - 配列の境界チェック: 動的なメモリアクセスに対してもRust標準のスライス境界検証が機能し、不正なメモリアドレスへの書き込みによるGPUカーネルクラッシュやメモリ破損を未然に防ぐ。
ロードマップと今後の展開
NVIDIAは、CUDA Rustを単発の実験的プロジェクトにとどめず、CUDAプラットフォームの主要構成要素として段階的に成熟させるロードマップを示している。
2026年後半から2027年にかけて予定されている主な項目。
- cuda-oxideのツールチェーン安定化: 現在のnightly Rust依存とカスタムLLVM要件を解消し、標準の
rustcアップストリームや公式ターゲットトリプルへの統合を進める。 - 多言語間の相互運用性の強化: CUDA C++やCUDA Pythonと同一プロセス内で混在利用できるよう、ランタイムABIおよびメモリレイアウトの相互運用インターフェースを拡充する。既存のC++カーネル資産を破棄することなく、特定のレイヤーのみをRustへ置き換える移行パスを提供する。
- CUDA Toolkitへの標準同梱: 将来のメジャーバージョンのCUDA Toolkitにおいて、CUDA Rustツールチェーンを標準コンポーネントとして配布し、インストーラーおよび公式ドキュメント群へ統合する。