A CUDA warp is already a 32-lane vector unit. OxiCUDA 0.5.4 is the first release to let you program it like one.
Today we released OxiCUDA 0.5.4 — a feature release adding WarpVec/WarpMask, a Simd/Mask-style expression layer over oxicuda-ptx’s builder DSL that treats a CUDA warp’s 32 lanes as a first-class vector value, plus the low-level warp shuffle/vote IR instructions it’s built on, and a new foreign-compiler PTX interop test proving the driver/launch stack correctly hosts rustc-generated PTX modules, not just oxicuda-ptx’s own.
No CUDA SDK. No nvcc. No C/C++ toolchain. OxiCUDA is a type-safe, memory-safe, pure-Rust replacement for the entire NVIDIA CUDA Toolkit software stack — cuBLAS, cuDNN, cuFFT, cuSPARSE, cuSOLVER, cuRAND, and more, across 74 crates and ~1.30M lines of safe Rust. libcuda.so/nvcuda.dll is loaded dynamically at runtime via libloading; nothing about building or running OxiCUDA requires the CUDA SDK, headers, or a C/C++ compiler. The result compiles to a single static binary and runs everywhere the driver is present.
Why OxiCUDA 0.5.4 is a game changer
Warp-level programming is where CUDA’s ergonomics fall apart fastest:
shfl.sync,vote.sync, andredux.syncare PTX-level primitives with four source-lane modes, sync masks, and segment widths to track by hand — get the mask or segment wrong and you get a silent wrong answer, not a compile error- Butterfly reductions, Hillis-Steele scans, and ballot-based counts are each a small, easy-to-get-subtly-wrong algorithm that most CUDA codebases reimplement (and re-debug) from scratch per kernel
- Mixing sub-warp-segmented operations with full-warp ones is a classic source of bugs, because nothing in raw PTX stops you from combining values that don’t share a segment width
- None of this is exposed as an ergonomic value type anywhere in the pure-Rust GPU stack — until now, warp-level code meant hand-emitting IR instructions directly
OxiCUDA 0.5.4 ends all of that.
WarpVecis a realSimd-style value type, not a wrapper over raw registers. It supports elementwise arithmetic (add/sub/mul/fma/min/max/neg/abs/sqrt/relu), with float multiplies correctly emittingmul.rn.f32/.f64rather than the integer.loform.- Butterfly all-reduce reductions (
reduce_sum/reduce_prod/reduce_min/reduce_max) automatically take aredux.syncfast path on sm_80+, and fall back cleanly on older architectures. WarpMaskcloses the comparison-to-branch loop: type-aware comparisons (gt/ge/lt/le/eq/ne) return aWarpMask, which addsand/or/xor/notlogic,any/all/ballot/count(segmented via ballot plus a segment mask), and mask-drivenselect.- Segment width is checked, not assumed. Both types carry a logical segment width (2..=32) validated on every binary op, so a segmented value can no longer be silently combined with a full-warp one.
- The full shuffle family is one API:
broadcast,shuffle_up/shuffle_down,butterfly,reverse, and dynamicshuffle_idx— all built on stable Rust via runtime PTX codegen, no nightly required.
Technical Deep Dive
- IR layer —
oxicuda-ptx. Six new instructions back the warp-vector layer:Shfl(shfl.sync, all four source-lane modes via the newShflModeenum),Vote(vote.sync, all/any/uni/ballot viaVoteMode),Mov(typed register/immediate moves with hex-exact float immediates),PackB64x2/UnpackB64x2(routing 64-bit values through the 32-bit-only shuffle datapath), andNot(incl.not.pred) — plusMulMode::Rnfor explicitmul.rn.f32/.f64. All six are fully wired into the validator’s def/use analysis, dead-code elimination, register-pressure tracking, instruction scheduling, arch-legality checks (sm_70 floor), and the interactive TUI explorer’s category/latency model. - Emission layer —
builder::warp_ops. The low-level primitives underWarpVec/WarpMask:lane_id,warp_index_x,mov_typed,shfl_sync/shfl_sync_with_valid(CUDA-exact segmentedc-operand encoding),vote_{all,any,uni,ballot}, andnot_pred. - Validation layer —
oxicuda-primitives. 11 on-devicegpu-tests, validated on an RTX A4000 (sm_86), exerciseWarpVec/WarpMaskagainst independent CPU oracles: relu-dot, theredux.syncfast path, s32/f64/segmented reductions, min/max, both scan directions, votes/ballot/count/segmented-any, and every shuffle mode. - Interop layer —
oxicuda-launch’srustc_ptx_interop. JIT-compiles and launches PTX fixtures produced by upstream nightlyrustc’s own NVPTX backend (nvptx64-nvidia-cuda) — notoxicuda-ptx’s generator — directly through the driver stack: a scalar SIMTsaxpyand acore::simd(portable-SIMD) relu-dot kernel, both checked for exact numerical agreement against a CPU oracle. Worth being precise here: the portable-SIMD fixture documents empirically that upstreamrustcscalarizesSimdwithin a single thread — noshfl.syncis emitted byrustcitself. The lane-to-warp mapping thatWarpVecprovides above isoxicuda-ptx’s own codegen layer, layered on top; it isn’t something stable Rust’score::simdgives you across a CUDA warp today.
Getting Started
cargo add oxicuda-ptx
A complete warp-level relu-dot-product kernel, generated entirely from Rust — no PTX written by hand:
use oxicuda_ptx::prelude::*;
fn main() {
let ptx = KernelBuilder::new("relu_dot_warp")
.target(SmVersion::Sm86)
.param("out", PtxType::U64)
.param("x", PtxType::U64)
.param("y", PtxType::U64)
.body(|b| {
let x_ptr = b.load_param_u64("x");
let y_ptr = b.load_param_u64("y");
let lane = b.lane_id();
let x_addr = b.f32_elem_addr(x_ptr, lane.clone());
let y_addr = b.f32_elem_addr(y_ptr, lane.clone());
let x_val = b.load_global_f32(x_addr);
let y_val = b.load_global_f32(y_addr);
let x = WarpVec::from_register(x_val).expect("f32 vec");
let y = WarpVec::from_register(y_val).expect("f32 vec");
// Elementwise multiply, ReLU, then a butterfly all-reduce sum
// across all 32 lanes -- redux.sync on sm_80+, shfl.sync below it.
let dot = x
.mul(b, &y).expect("mul")
.relu(b).expect("relu")
.reduce_sum(b).expect("reduce");
// Lane 0 stores the warp's aggregate.
let out_ptr = b.load_param_u64("out");
let one = b.mov_imm_u32(1);
b.if_lt_u32(lane, one, |b| {
b.store_global_f32(out_ptr.clone(), dot.register().clone());
});
b.ret();
})
.build()
.expect("PTX generation failed");
assert!(ptx.contains("shfl.sync.bfly.b32"));
println!("Generated {} bytes of PTX using a butterfly warp-shuffle reduction", ptx.len());
}
This is the same kernel shape validated on real hardware. To run the equivalent on your own GPU:
cargo test --features gpu-tests -p oxicuda-primitives
What’s New in 0.5.4
WarpVec/WarpMaskadded tooxicuda-ptx(exported fromoxicuda_ptx::preludealongsideWarpReduceOp,WarpScanMode,FULL_WARP_MASK,WARP_SIZE) — elementwise arithmetic, type-aware comparisons,select, butterfly all-reduce reductions, a -0.0-preserving Hillis-Steelescan_sum, and the full shuffle family.- Six new IR instructions (
Shfl,Vote,Mov,PackB64x2/UnpackB64x2,Not) fully wired into validation, dead-code elimination, register-pressure tracking, scheduling, and arch-legality checks. oxicuda-primitives: 11 new on-devicegpu-tests, validated on an RTX A4000 (sm_86) against independent CPU oracles.oxicuda-launch: newrustc_ptx_interopgpu-tests prove the driver/launch stack hosts PTX from upstreamrustc’s own NVPTX backend, including acore::simdkernel — while documenting thatrustcitself still scalarizesSimdwithin a thread today.- Fixed:
Instruction::Redux’s bitwise reduction ops (and/or/xor) were emitted as.u32when the PTX ISA requires the untyped.b32form —ptxasrejected every bitwise warp reduction until this release; the arithmetic ops (add/min/max) were unaffected. - Test suite expanded to 38,689 passing tests (
--all-features; 37,346 with default features), up from 38,675/37,320 at 0.5.3.
Tips
- Import everything from one place:
use oxicuda_ptx::prelude::*;brings inWarpVec,WarpMask,WarpReduceOp,WarpScanMode,FULL_WARP_MASK, andWARP_SIZEtogether. - Prefer
.reduce_sum()/.reduce_max()etc. over hand-rolledshfl.syncloops. On sm_80+ they take theredux.syncfast path automatically; below sm_80 they fall back to a butterfly shuffle reduction — same call site either way. - Let the segment-width check catch your bugs for you.
WarpVec/WarpMaskvalidate a logical segment width (2..=32) on every binary op, so accidentally combining a segmented value with a full-warp one is now a caught error instead of a silently wrong reduction. - Don’t expect
core::simdto vectorize across a warp on its own yet. The newrustc_ptx_interoptest shows upstreamrustc’s NVPTX backend still scalarizesSimdwithin a single thread — noshfl.syncemitted.WarpVec’s lane-to-warp mapping isoxicuda-ptx’s own codegen layer; it’s how you get warp-level SIMD in OxiCUDA today, not something stablecore::simdprovides across a CUDA warp by itself. - If you hand-rolled bitwise warp reductions before 0.5.4, upgrade —
redux.sync.and/.or/.xorwere being rejected byptxasoutright, so if it compiled for you, you were on the arithmetic path, not the bitwise one. - Run the hardware validation yourself:
cargo test --features gpu-tests -p oxicuda-primitivesexercises all 11 newWarpVec/WarpMaskcases against CPU oracles on real silicon.
This is the foundation
OxiCUDA is the GPU layer beneath the rest of the COOLJAPAN ecosystem. Its architecture diagram puts SciRS2, OxiONNX, TrustformeRS, and ToRSh directly on top of it, with OxiBLAS and OxiFFT rounding out the list of projects that lean on this stack — and the oxicuda crate itself is an umbrella re-export over all 74 crates, so a single cargo add oxicuda pulls in whichever subsystem a dependent project needs. Every kernel-generating crate built on oxicuda-ptx can reach for WarpVec/WarpMask starting today.
Repository: https://github.com/cool-japan/oxicuda
Star the repo if you think warp-level parallelism deserves a Simd-style API instead of hand-rolled shfl.sync calls. Every star tells us to keep building.
The era of hand-written warp-shuffle boilerplate is over. Pure Rust GPU computing is here — and as of 0.5.4, your CUDA warps get a Simd-style vector API to match.
— KitaSan at COOLJAPAN OÜ August 12, 2026