Repository navigation
Emit LLVM noalias / readonly for Rust references with proven semantics #1088
Copy link
Copy link
Open
Labels
DependsBlocked on another PR/issue or an upstream dependencyBlocked on another PR/issue or an upstream dependencyIR-loweringLowering between dialects (dialect-mir to LLVM dialect)Lowering between dialects (dialect-mir to LLVM dialect)codegenDevice code-generation pipeline (Rust MIR to IR to PTX)Device code-generation pipeline (Rust MIR to IR to PTX)llvm-exportTextual LLVM/NVVM IR exporter (llvm-export crate)Textual LLVM/NVVM IR exporter (llvm-export crate)perfPerformance of generated code or of the compiler itselfPerformance of generated code or of the compiler itselfquestionFurther information is requestedFurther information is requestedsoundness-auditCorrectness case under active maintainer audit; not cleared for merge yetCorrectness case under active maintainer audit; not cleared for merge yet
Description
Motivation
Part of #413.
After #1062 preserves Rust pointer/reference kind through dialect MIR, the compiler can distinguish:
&T→SharedRef&mut T→UniqueRef*const T→RawConst*mut T→RawMut- compiler-generated / erased pointers →
Erased
This makes it possible to attach LLVM parameter attributes when the corresponding Rust semantics are actually proven, instead of inferring them from the lowered pointer type.
This matters for optimization. In particular, alias information can enable substantially better load/store optimization and vectorization for reference-based kernels.
Proposed semantics
Follow rustc's conservative reference rules:
| Rust parameter | Condition | LLVM attributes |
|---|---|---|
&T, &[T] |
pointee is Freeze |
noalias readonly |
&mut T, &mut [T] |
pointee is Unpin |
noalias |
*const T |
— | none |
*mut T |
— | none |
| erased / compiler-generated pointer | — | none |
In particular:
&UnsafeCell<T>must not receivereadonly- shared references should not receive aliasing attributes unless the
Freezerequirement is satisfied - mutable references should not receive
noaliasunless theUnpinrequirement is satisfied - raw pointers must not receive reference-derived attributes
DisjointSliceshould remain uninterpreted for this change
Implementation outline
- During MIR import, inspect the original rustc parameter type while the semantic information is still available.
- Record only proven per-source-argument facts on
MirFuncOp. - Preserve those facts through MIR lowering.
- Remap source arguments to their physical LLVM parameters after ABI flattening.
- For slices, attributes apply only to the pointer component, not the length field.
- Make
llvm-exportmechanically serialize the already-proven facts.- The exporter must not infer aliasing from pointer type, mutability, address space, or
DisjointSlice.
- The exporter must not infer aliasing from pointer type, mutability, address space, or
Acceptance criteria
&T/&[T]withFreezeemitnoalias readonly&UnsafeCell<T>emits neither attribute&mut T/&mut [T]withUnpinemitnoalias&mut !Unpinemits no reference-derived attribute- raw pointers emit no reference-derived attributes
- slice metadata parameters are never annotated
- invalid attribute combinations are rejected
- legacy typed-pointer LLVM export continues to work
- existing CUDA examples continue to build
- end-to-end generated LLVM IR contains the expected attributes
Out of scope
dereferenceable- recursive alias analysis
- deriving attributes from
DisjointSlice - deriving attributes from raw pointers
- alias inference based on LLVM-level pointer shapes
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
DependsBlocked on another PR/issue or an upstream dependencyBlocked on another PR/issue or an upstream dependencyIR-loweringLowering between dialects (dialect-mir to LLVM dialect)Lowering between dialects (dialect-mir to LLVM dialect)codegenDevice code-generation pipeline (Rust MIR to IR to PTX)Device code-generation pipeline (Rust MIR to IR to PTX)llvm-exportTextual LLVM/NVVM IR exporter (llvm-export crate)Textual LLVM/NVVM IR exporter (llvm-export crate)perfPerformance of generated code or of the compiler itselfPerformance of generated code or of the compiler itselfquestionFurther information is requestedFurther information is requestedsoundness-auditCorrectness case under active maintainer audit; not cleared for merge yetCorrectness case under active maintainer audit; not cleared for merge yet
Activity
nihalpasham commentedon Aug 24, 2026
Keeping this open as a design question, but implementation is blocked for now.
noaliasorreadonly.noalias/readonlyfor Rust references with proven semantics #1088 and Emit LLVMnonnull/align/dereferenceablefor proven Rust references #1098 as one reference-attribute policy after Preserve Rust reference kind and exclusivity through MIR import and lowering #413. Derive each fact from the pinned rustc ABI rules, and carry that proof separately from the pointer representation.UnsafeCell, pinned types, and argument flattening.An incorrect optimizer promise can silently miscompile valid code, so the full proof is required under the current acceptance criteria.
nihalpasham commentedon Sep 3, 2026
Building on #1186: the pointer kinds are in, minted from rustc_public only, but a kind is a classification, not an aliasing proof (the gap #1089 was closed for).
One rule for the design: every fact comes through
rustc_public. NoTyCtxtreads, noDebug-stringparsing.What
rustc_publiccan prove today, and what it cannot:nonnull/alignhalf (Emit LLVMnonnull/align/dereferenceablefor proven Rust references #1098) can be built now from kind + layout.noalias/readonly/dereferenceablerustc_publicto expose typedArgAttributesinPassMode(todayOpaque).mir.funcper source argument;NVVMpath only ifnvvmVerifyProgramaccepts.len,DisjointSlice,&UnsafeCell<T>,&mutof a!Unpintype,&[DeviceAtomicU32],extern "C"kernel all print bare.@uurl - Do you want to take the
nonnull/alignhalf now? An approach note here first would be great.nihalpasham commentedon Sep 3, 2026
Filed the upstream ask for typed
ArgAttributesin rustc_public: rust-lang/rustc_public#132.uurl commentedon Sep 25, 2026
@nihalpasham — I saw rust-lang/rust#163242 is now up for review.
Once that lands and cuda-oxide picks up the corresponding rustc version, are you planning to take the downstream #1088 / remaining #1098 integration, or would you like me to take it?
I'd be happy to build on the reference-attribute plumbing from #1244 and keep the importer as a straight copy of rustc's typed
ArgAttributesdecisions, without re-derivingFreeze/Unpinsemantics.praveenperera commentedon Oct 10, 2026
A data point for this, from a speakrs repro on
main(bafffe45), sm_80, ptxas 13.0.88:A kernel that copies 16-byte pixels from an
input: &[f32]parameter by casting to*const U32x4emitsld.global.v4.b32(LDG.E.128), but neverld.global.nc. The same happens with*const f32and withvector::as_vectors::<F32x4>(input).#[readonly]is a function-level marker for extern device functions, so there's currently no way to get the non-coherent path for a read-only input.In speakrs's FP16 convolution kernels (https://github.com/avencera/speakrs,
crates/speakrs-cuda-kernels/src/wideconv/h16.rs), inputs that no kernel writes during the launch, such as weights and staged activations, are read withptx_asm!usingld.global.nc.f32,ld.global.nc.v2.u32andld.global.nc.v4.u32. If&[T]with aFreezepointee gotnoalias readonlyas proposed here, NVPTX could selectld.global.ncitself, and we could drop that asm. An explicit.ncload intrinsic for raw pointers would cover the cases where the input isn't a reference.uurl commentedon Oct 11, 2026
@nihalpasham — now that rust-lang/rust#163242 has landed, and given the new speakrs data point above, are you planning to take the downstream #1088 / remaining #1098 integration once cuda-rust picks up a nightly containing ArgAttributes::regular(), or would you like me to take it?
I’d be happy to build on #1244 and keep the importer as a straight copy of rustc’s typed ArgAttributes decisions (no_alias, read_only, no_free, pointee_size), without re-deriving Freeze / Unpin.
cuda-oxide: update to nightly-2026-10-11 (#1482)
nihalpasham commentedon Oct 11, 2026
The remaining explicit
readonlywork has an upstream blocker: LLVM #230960. Withnoalias readonly, NVPTX drops volatility and two required reads can become one machine load. This reproduces on LLVM 22.1.8, 23.1.0, and 23.1.3.#1483 adds rustc-proven
noaliaswhile deferring explicit kernelreadonly. Keeping this issue open for that remaining work; the report includes the reduced IR and the working control.cuda-oxide: preserve rustc reference attributes on kernels (#1483)