Skip to content

Rustlantis: support Static and StaticMut operands in custom MIR #1162

Open

Description

@uurl

Description

Rustlantis currently supports Copy, Move, and Constant operands, but custom MIR also provides Static and StaticMut for creating pointers to static allocations.

The corresponding TODO is already present in mir/src/syntax.rs:

// define!("mir_static", fn Static<T>(s: T) -> &'static T);
// define!("mir_static_mut", fn StaticMut<T>(s: T) -> *mut T);

Supporting these operands would extend Rustlantis coverage to MIR programs that access static and mutable static allocations.

Expected behavior

Rustlantis should be able to generate and serialize:

Static(S)
StaticMut(T)

with corresponding top-level static declarations.

The generated pointers should integrate with the existing place graph and memory model so that:

  • static allocations remain alive independently of function frames
  • Static produces a shared reference to the static allocation
  • StaticMut produces a mutable raw pointer to the static allocation
  • subsequent dereferences and assignments use the existing pointer and alias tracking

Initial scope

A minimal implementation can start with scalar static initializers and existing pointer/reference types.

More complex cases such as aggregate initializers, statics containing pointers, TLS, or arbitrary constant expressions can remain out of scope initially.

Activity

  1. added
    enhancementNew feature or request
    fuzzerFuzzing infrastructure (rustlantis, difftest)
    questionFurther information is requested
    on Aug 24, 2026
  2. nihalpasham commented on Aug 24, 2026

    @nihalpasham
    Collaborator

    This is not actionable yet as a coverage-only feature.

    • Please identify a concrete fuzzing gap, bug class, or workload that requires Static and StaticMut.
    • Static declarations must survive the production adapter. extract_first_custom_mir_fn currently drops everything before the custom-MIR function, leaving references such as Static(static0) without a definition.
    • Provide a fail-before/pass-after generated program through the real adapter and host/CUDA compiler paths, with resolved symbols, runtime behavior, and an unaffected control.

    The linked implementation tested the pieces separately, so it did not prove that Rustlantis can produce a usable program. Please reframe this around that full path and the current acceptance criteria.

  3. nihalpasham commented on Sep 3, 2026

    @nihalpasham
    Collaborator

    Picking this up with the concrete gap that was missing from the first framing.

    • Ordinary device statics (a Rust static that lives in GPU global memory, addrspace 1) go through a path only cuda-oxide has: hex initializer image, immutable flag, address-space normalization. Nearly all of the roughly twenty static issues closed since July were initializer relocations or debug info (debug: fix LLVM 23 silently dropping device debug info for kernel-local statics #1216 landed yesterday). At runtime only the hand-written device_global example reads and writes one. That is the gap: random write-then-read sequences over device statics, compared CPU vs GPU.
    • StaticMut is the leg that matters. cargo oxide run builds --release, so rustc's GVN folds *Static(s) of a scalar to its initializer before the translator ever sees it. A *mut T from StaticMut is never folded.
    • Scope I would take: scalar statics only, behind a generator config knob that defaults to 0 (gating both the static minting and the extra RNG draw) so every existing seed still reproduces.
    • The adapter (crates/fuzzer/tools/mir_generator.py, which turns one rustlantis program into generated_case.rs) must carry the static lines along. Today extract_first_custom_mir_fn returns the text from #[custom_mir onward, so they are lost. Add non_upper_case_globals to its allow list, since rustlantis names them static0. No unsafe wrapping is needed; custom-MIR bodies skip unsafety checking.
    rustlantis output                 generated_case.rs
    static mut static0: u32 = 7_u32;  static mut static0: u32 = 7_u32;  <- carried by the adapter
    #[custom_mir] pub fn fn1() {      #[custom_mir] fn fn1() {
      _2 = StaticMut(static0);          _2 = StaticMut(static0);
      _3 = (*_2);                       _3 = (*_2);            <- initializer image
      (*_2) = 9_u32;                    (*_2) = 9_u32;
      _4 = (*_2); dump_var(_3, _4)      _4 = (*_2); dump_var(_3, _4)  -> CPU trace == GPU trace
    }                                 }
    
    • Evidence for the PR, through run_seed.py: one seed with a StaticMut read, write, read. Fail-before: today's adapter gives a rustc error on the undefined static0. Pass-after: traces match and the .ptx contains the .global symbol. Control: seed 33 with the knob at 0 is byte-identical to main. Keep the checked-in generated_case.rs as is; it covers the libdevice path.
    • The generator and place-graph pieces from feat(fuzzer): generate Static and StaticMut operands #1163 can come back as they were.
    • Sequencing: this lands after the Support chained projected destinations for call and intrinsic results #1164 ordering fix, since generated call destinations go through the store path that fix rewrites; a static used as a call destination would otherwise produce ambiguous differential results.

    Acceptance criteria for reference: https://discord.com/channels/1515530041767759993/1515561621156663487/1540970771323551775

    Do you want to take it under that scope?

  4. uurl commented on Sep 3, 2026

    @uurl
    ContributorAuthor

    Yes @nihalpasham , I’ll take it under that scope. I’ll sequence it after the #1164 ordering fix, keep it to scalar statics behind a default-zero generator knob, preserve existing seed reproducibility, and validate the StaticMut read/write/read path through run_seed.py with the fail-before/pass-after and byte-identical control you specified.

  5. nihalpasham commented on Sep 15, 2026

    @nihalpasham
    Collaborator

    Reviewed #1245: partial; valid global alias generation remains open.

    • Initializer preservation and mutable read/write/read are demonstrated on GPU.
    • With static count zero, the checked seed output is unchanged.
    • Reacquiring a global currently grants fresh graph access despite a live exclusive reference. The generator needs one consistent provenance rule across calls before this is ready.

    The successful scalar seed covers the alias-free path; it does not settle that model gap. Keeping this issue open.

  6. nihalpasham commented on Sep 18, 2026

    @nihalpasham
    Collaborator

    I rechecked #1245 and requested further changes.

    A write through a static root can invalidate a shared reference's tag while reference selection still accepts it. Passing that reference into a call then panics during protection. The wider generator checks also found regressions with the static count set to zero; the earlier tiny-seed control did not cover those configurations.

    The alias bookkeeping and disabled-feature compatibility need to hold together before this covers the requested static generation. The successful scalar GPU example does not establish that yet.

  7. added
    cuda-oxideSIMT programming model: rustc backend, cargo oxide, cuda-device, cuda-host, book
    on Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    cuda-oxideSIMT programming model: rustc backend, cargo oxide, cuda-device, cuda-host, bookenhancementNew feature or requestfuzzerFuzzing infrastructure (rustlantis, difftest)questionFurther information is requestedtestsAdds or improves test coverage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions