Skip to content

fix(mir-importer): adapt shared pointers at ordinary call boundaries - #3

Merged
midagedev merged 1 commit into
midagedev:bloomeryfrom
juliankang4:fix/shared-pointer-call-argument
Oct 25, 2026
Merged

midagedev merged 1 commit into
midagedev:bloomeryfrom
juliankang4:fix/shared-pointer-call-argument

Conversation

@juliankang4

@juliankang4 juliankang4 commented Oct 25, 2026 •

Copy link
Copy Markdown

Summary

Backport the ordinary-call pointer adaptation from NVIDIA/cuda-rust commit 927d462eebe1ca2dde13439ef37c44184eadbb13 (NVIDIA#1598) onto bloomery. A pointer from DynamicSharedArray retains shared address space 3, while a Rust helper's raw-pointer parameter uses generic address space 0. Without the adaptation, MIR call verification rejects the argument before code generation.

Changes

  • Add the upstream call-site block to emit_function_call, using the existing normalize_foreign_pointer_argument helper under its current name. Pointee, mutability and pointer kind must still agree.
  • The examples-compile workflow builds both shared_memory_helper variants (local-helper and cross-crate-helper) on main and bloomery, both with #[inline(never)].
  • Update the example's documented contract. Keep the current Rust toolchain and the other fork patches.

This targets midagedev/cuda-oxide:bloomery, whose previous pin is 87bc951864b79f723b4da9c11fa229f5600aefcb. It does not overlap the tool-selection files in #2.

Before merging, tag the current bloomery tip as pin/87bc9518 to preserve the previous pin.

Testing

On a DGX Spark (NVIDIA GB10, driver 595.84 reporting CUDA driver API 13.3), using the pinned nightly-2026-08-28 toolchain (rustc 1.100.0-nightly e457a7b0d):

  • At 87bc951864b79f723b4da9c11fa229f5600aefcb, both helper builds exited 101 with MirCallOp argument 0 type does not match callee signature.
  • With this change, both helper builds and their binaries succeeded. Each reported 9 launches, 36 CTA data/barrier checks; the direct control reported the same count.
  • cargo test -p mir-importer --lib foreign_pointer_argument: 4 passed; 0 failed.

Reproduce from cuda-oxide/ with the pinned toolchain:

set -e
cargo oxide build shared_memory_helper --arch sm_121a --features local-helper
crates/rustc-codegen-cuda/examples/shared_memory_helper/target/release/shared_memory_helper
cargo oxide build shared_memory_helper --arch sm_121a --features cross-crate-helper
crates/rustc-codegen-cuda/examples/shared_memory_helper/target/release/shared_memory_helper
cargo test -p mir-importer --lib foreign_pointer_argument
  • just check (full CI mirror; not run here).
  • Both helper variants build and their binaries pass the data/barrier checks.
  • New example added (not applicable; the existing example covers this boundary).

What I ran into

This does not block the PR. Full just check and Compute Sanitizer were not run here.

Checklist

  • All commits signed off (git commit -s). The commit attributes the upstream block and retains its original sign-off.
  • SPDX headers on new source files (not applicable; no source file added).

Backported from NVIDIA/cuda-rust 927d462 (NVIDIA#1598) by
nihalpasham <[email protected]>.

Reuse the existing normalization helper under its current name and
preserve its type and provenance checks for ordinary Rust calls.

Build both non-inlined shared-memory helper variants in the workflow on
main and bloomery, and document their call-boundary contract.

Signed-off-by: nihalpasham <[email protected]>
Signed-off-by: juliankang4 <[email protected]>
@midagedev
midagedev merged commit 466ee16 into midagedev:bloomery Oct 25, 2026
@midagedev

Copy link
Copy Markdown
Owner

Thanks for this backport. We are moving bloomery off the fork, to depend on NVIDIA/cuda-rust directly.

The upstream commit with this fix (927d462, NVIDIA#1598) also adds the cute verifier. On our crates it is quadratic in kernel size and runs on every scope, so crates/gpu does not finish building (1700 s timeout; 388 s before that commit).

We will work around the verifier in bloomery and move to upstream HEAD today, so this fix lands in bloomery. The verifier defect goes upstream as a separate PR.

@midagedev

Copy link
Copy Markdown
Owner

What we found so far on the slow build, so you do not have to start over.

Where the time goes: two gdb stacks on rustc for bloomery_gpu, taken 15 s apart, are both in
verify_cute_semantics -> verify_pipeline_story -> build_pipeline_facts -> poison_missing_forwarding_sources -> OrdinaryFacts::entries.
entries scans the whole fact map for each store and block argument. The map holds every integer SSA value of 32 bits or less in the kernel scope. So the pass is quadratic in kernel size. It runs on every scope, including modules with no CuTe op.

Build times on the box (cold cargo oxide build --bin generate_ds41, 12 jobs, one tree, only the pin differs):

  • HEAD 9df9e7c + stable 1.99.1: timed out at 1700 s
  • 0143af5 (= 927d462^): 388 s
  • HEAD + the guard below: 483 s

The guard skips a scope that holds no CuTe semantic op. An indexed lookup in OrdinaryFacts may be the better upstream fix.

scope guard (dialect-cute/src/verify)
--- ghosts.rs	2026-10-26 06:13:11.127219447 +0900
+++ cuda-oxide/cute-rs-preview/dialect-cute/src/verify/ghosts.rs	2026-10-26 07:00:55.183837939 +0900
@@ -150,7 +150,7 @@
 }
 
 /// Collect the closed set of operations allowed to carry semantic ghosts or metadata.
-fn all_high_level_semantic_ids() -> Vec<OpId> {
+pub(super) fn all_high_level_semantic_ids() -> Vec<OpId> {
     let mut ids = tensor_semantic_ids().to_vec();
     ids.push(crate::ops::copy::CuteStoreGlobalNoAllocateOp::get_opid_static());
     ids.extend(gemv_semantic_ids());
--- mod.rs	2026-10-26 06:13:11.127219447 +0900
+++ cuda-oxide/cute-rs-preview/dialect-cute/src/verify/mod.rs	2026-10-26 07:00:55.183837939 +0900
@@ -52,7 +52,7 @@
 use cfg::operations_by_scope;
 use epilogue::verify_epilogue_story;
 use gemv::verify_gemv_story;
-use ghosts::audit_cute_ghosts;
+use ghosts::{all_high_level_semantic_ids, audit_cute_ghosts};
 pub use ghosts::type_contains_cute_ghost;
 use mma::verify_smem_mma_story;
 use pipeline::verify_pipeline_story;
@@ -297,7 +297,17 @@
         verify_local_op(ctx, *operation)?;
     }
     audit_cute_ghosts(ctx, &all_ops)?;
+    let semantic_ids = all_high_level_semantic_ids();
     for scope in operations_by_scope(ctx, module, &all_ops) {
+        // A scope with no CuTe semantic operation has no story to verify. Each story builds provenance
+        // facts, and `OrdinaryFacts::entries` scans the whole fact map for every store, so a large SIMT
+        // kernel would cost time quadratic in its size for nothing.
+        if !scope
+            .iter()
+            .any(|operation| semantic_ids.contains(&Operation::get_opid(*operation, ctx)))
+        {
+            continue;
+        }
         verify_scheduler_story(ctx, &scope)?;
         verify_pipeline_story(ctx, &scope)?;
         verify_tma_story(ctx, &scope)?;

@midagedev

midagedev commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner

Correction to my last comment: the verify time is cubic, not quadratic. The fixpoint rounds grow with the block count, and each round scans the whole fact map. 800 blocks: 248 s without the guard, 0.005 s with it.

Filed upstream with the patch and a timing test: NVIDIA#1647. bloomery is moving to upstream 9df9e7c and will carry this one patch until upstream takes a fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants