Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions .github/workflows/examples-compile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ name: examples-compile
# Path-filtered SIMT lane (same roots as ci.yml).
on:
push:
branches: [main]
branches: [main, bloomery]
paths:
- 'cuda-oxide/**'
- 'cuda-bindings/**'
Expand All @@ -15,7 +15,7 @@ on:
- 'Cargo.lock'
- '.github/workflows/**'
pull_request:
branches: [main]
branches: [main, bloomery]
paths:
- 'cuda-oxide/**'
- 'cuda-bindings/**'
Expand Down Expand Up @@ -129,6 +129,25 @@ jobs:

cuda-oxide/scripts/smoketest.sh --compile-only --no-color

- name: Compile shared-memory helper calls
timeout-minutes: 10
working-directory: cuda-oxide
env:
CUDA_TOOLKIT_PATH: ${{ steps.cuda-toolkit.outputs.CUDA_PATH }}
CUDA_OXIDE_LLC: /usr/bin/llc-22
CARGO_TARGET_DIR: ${{ runner.temp }}/examples-shared-target
CARGO_INCREMENTAL: "0"
run: |
set -euo pipefail
sysroot="$(rustc --print sysroot)"
export LIBRARY_PATH="${sysroot}/lib:${LIBRARY_PATH:-}"
export LD_LIBRARY_PATH="${sysroot}/lib:${LD_LIBRARY_PATH:-}"

for features in local-helper cross-crate-helper; do
cargo oxide build shared_memory_helper --arch sm_90 --features "$features" \
2>&1 | tee "${RUNNER_TEMP}/shared-memory-${features}-build.log"
done

- name: Artifact modes keep shared Cargo dependencies fresh
timeout-minutes: 10
working-directory: cuda-oxide
Expand Down Expand Up @@ -266,6 +285,7 @@ jobs:
# `if-no-files-found: ignore` below made that silent.
path: |
${{ runner.temp }}/smoketest-logs/
${{ runner.temp }}/shared-memory-*-build.log
${{ runner.temp }}/vecadd-*-build.log
${{ runner.temp }}/iket-trace-*-build.log
${{ runner.temp }}/cross-crate-*-build.log
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,45 @@ pub fn emit_function_call(
}
}

// Ordinary Rust helper signatures also expose generic pointers. Resolve
// the monomorphized operand type (not an unresolved trait signature), and
// adapt only address space. All other type/provenance mismatches still
// reach the independently typed callee's verifier unchanged.
if external_callee_type.is_none() {
for (argument, operand) in arg_values.iter_mut().zip(args) {
if argument
.get_type(ctx)
.deref(ctx)
.downcast_ref::<MirPtrType>()
.is_none()
{
continue;
}
let rust_type = match operand.ty(body.locals()) {
Ok(ty) => ty,
Err(error) => {
return input_err!(
loc.clone(),
TranslationErr::unsupported(format!(
"failed to resolve Rust call argument type: {error:?}"
))
);
}
};
let declared = crate::translator::types::translate_type(ctx, &rust_type)?;
let (normalized, tail) = normalize_foreign_pointer_argument(
ctx,
*argument,
declared,
block_ptr,
last_op,
loc.clone(),
);
*argument = normalized;
last_op = tail;
}
}

let (prepared_destination, prepared_last_op) = prepare_destination_write(
ctx,
body,
Expand Down Expand Up @@ -445,8 +484,8 @@ pub fn emit_function_call(
}
}

/// Adapt a foreign-call pointer argument only when the address space is the
/// sole difference from its declared ABI parameter type.
/// Adapt a foreign or Rust call pointer argument only when the address space
/// is the sole difference from its declared parameter type.
fn normalize_foreign_pointer_argument(
ctx: &mut Context,
value: Value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,8 @@ cargo oxide build shared_memory_helper --arch sm_120a
crates/rustc-codegen-cuda/examples/shared_memory_helper/target/release/shared_memory_helper
```

Build each helper variant separately; these currently fail as described below.
Do not run a binary left over from the successful control build as evidence
that a failed helper build worked.
Build each helper variant separately, then run its binary with the same
sanitizer commands. Stop on a failed build to avoid running a stale binary.

```bash
cargo oxide build shared_memory_helper \
Expand All @@ -67,49 +66,18 @@ Repeat with `--features local-helper,force-inline`,
`cross-crate-helper,heuristic-inline` to compare inlining policies.
Set `CUDA_OXIDE_DUMP_MIR=1` to inspect the imported helper definition and call.

## Observed results
## Expected results

Tested on 2026-09-17 against `main` at
`7ce30ec798c490e6ed772dfcbad193b3733fe55a`, with this example added, on an
RTX 5090, NVIDIA driver 580.173.02, and CUDA tools 13.3.
The direct control and both helper variants must build and report a `PASS`
marker after checking the data and barrier results. The `examples-compile`
workflow builds both helper variants on `main` and `bloomery` with their
default `#[inline(never)]` policy.

| Variant | Result |
| --- | --- |
| Direct control | Builds; GPU checks pass |
| Local helper, all three inline policies | MIR verification rejects the call |
| Dependency helper, all three inline policies | Same rejection |

Both Compute Sanitizer runs of the direct control reported:

```text
PASS direct: 9 launches, 36 CTA data/barrier checks
========= ERROR SUMMARY: 0 errors
```
The imported argument has address space 3 (shared memory), while the helper
parameter has address space 0 (generic memory). The importer adapts that
address-space difference before call verification. Pointee, mutability and
pointer kind must still match.

All six helper builds failed with:

```text
MirCallOp argument 0 type does not match callee signature
```

The imported call passes `mir.ptr<ui8, mutable:true, addrspace:3, kind:RawMut>`
(shared memory), while the helper parameter is
`mir.ptr<ui8, mutable:true, addrspace:0, kind:RawMut>` (generic memory). The
helper body is present in the imported module, including for the dependency
crate. Ordinary Rust calls do not receive the address-space adaptation that
the importer applies to foreign calls. Strict call verification rejects the
mismatch before backend code generation. Requesting `inline(always)` did not
remove the call before this verification in the tested builds.

This reproduces a compile-time rejection of this raw-byte-pointer boundary.
It does not demonstrate silent miscompilation or prove runtime correctness
of a surviving helper call, because no helper variant reached GPU execution.
The dependency test imports available MIR across crates; it does not test an
opaque, separately linked device binary. The runtime control checks one-thread
The dependency variant imports available MIR across crates; it does not test
an opaque, separately linked device binary. The runtime checks one-thread
barrier behavior, not synchronization between multiple threads or TMA traffic.

The diagnostic currently exposes an internal MIR mismatch. This reproducer
does not change the diagnostic or implement the missing call conversion.
Pointers whose pointee is `Barrier` or `SharedArray` already receive a shared
address space, so this result should not be generalized to every helper that
accepts shared memory.