Skip to content
Open
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
132 changes: 132 additions & 0 deletions contrib/godbolt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Compiler Explorer (Godbolt) Integration for rust-cuda

This directory contains everything needed to add rust-cuda as a compiler on
[Compiler Explorer](https://compiler-explorer.com/) so that users can type
Rust GPU kernel code and see the resulting PTX assembly.

## How it works

Compiler Explorer expects a single "compiler" binary that reads source on
stdin or from a file and writes assembly to stdout. Since rust-cuda has no
standalone compiler (the pipeline is `rustc` with a custom codegen backend
plus `cargo` for dependency resolution), the integration uses a small Rust
wrapper binary that:

1. Accepts a `.rs` file containing `#[kernel]` functions.
2. Creates a temporary Cargo project that depends on `cuda_std`.
3. Sets `CARGO_ENCODED_RUSTFLAGS` with the same flags `cuda_builder` uses
(codegen backend path, `no_std` injection, `nvptx64-nvidia-cuda` target,
`-Zbuild-std=core,alloc`, etc.).
4. Runs `cargo build` and parses the JSON output to locate the `.ptx` artifact.
5. Prints the PTX to stdout (or LLVM IR if `--emit=llvm-ir` is passed).
6. Forwards compiler diagnostics to stderr so CE displays them.

## Files

| File | Purpose |
|------|---------|
| `rust-cuda-wrapper/` | Rust crate for the wrapper binary CE invokes as the "compiler" |
| `rust-cuda.defaults.properties` | CE configuration (compiler type, flags, defaults) |
| `rust-cuda.amazon.properties` | CE instance-specific overrides for the AWS fleet |
| `install.sh` | Installs the pinned nightly, builds the codegen backend and the wrapper, and lays out the prefix |
| `test-kernel.rs` | Sample kernel with shared memory and thread indexing |

## Supported flags

| Flag | Description |
|------|-------------|
| `--emit=ptx` | Output PTX assembly (default) |
| `--emit=llvm-ir` | Output LLVM IR before libnvvm conversion |
| `--opt-level=0` | Disable optimisations |
| `--opt-level=3` | Enable optimisations (default) |
| `--gpu-arch=sm_XX` | Target GPU compute capability (default `sm_75` / Turing) |
| `--version` | Print version info |

## Testing locally

### Prerequisites

- CUDA toolkit installed (need `libnvvm` in `$CUDA_PATH/nvvm/lib64/`)
- The Rust nightly pinned in `rust-toolchain.toml` (`nightly-2026-04-02`)
- A built `librustc_codegen_nvvm.so`

### Quick test

```bash
# From the rust-cuda repo root, after building the codegen backend:
export RUST_CUDA_ROOT=/opt/compiler-explorer/rust-cuda # or your install prefix
export CUDA_PATH=/usr/local/cuda

# Run install.sh first (or manually arrange the prefix):
./contrib/godbolt/install.sh

# Then test:
$RUST_CUDA_ROOT/bin/rust-cuda-wrapper contrib/godbolt/test-kernel.rs
```

You should see PTX assembly printed to stdout.

### Without install.sh

If you already have the codegen backend built in the workspace, you can
point the wrapper at the repo tree directly:

```bash
export RUST_CUDA_ROOT=/path/to/rust-cuda
# Ensure $RUST_CUDA_ROOT/lib/librustc_codegen_nvvm.so exists.

cd contrib/godbolt/rust-cuda-wrapper
cargo run --release -- ../test-kernel.rs
```

### Running the integration test

The wrapper crate ships a smoke test that compiles `test-kernel.rs`
end-to-end and asserts the output looks like PTX:

```bash
cd contrib/godbolt/rust-cuda-wrapper
cargo test # skips without RUST_CUDA_ROOT
RUST_CUDA_ROOT=/path/to/rust-cuda cargo test # runs the real build
```

## Submitting to Compiler Explorer

1. Open an issue on [compiler-explorer/compiler-explorer](https://github.com/compiler-explorer/compiler-explorer)
proposing the new compiler, linking to this directory.
2. Open a PR on [compiler-explorer/infra](https://github.com/compiler-explorer/infra)
that adds `install.sh` to the builder configuration.
3. Copy `rust-cuda.defaults.properties` into
`etc/config/` in the compiler-explorer repo.
4. Copy `rust-cuda.amazon.properties` into the appropriate instance
config directory.

Key things CE maintainers will want to verify:

- The wrapper is sandboxed (it only writes to `$TMPDIR` and cleans up).
- Build times are acceptable (first build is slow due to `-Zbuild-std`; subsequent
builds reuse the sysroot cache).
- The CUDA toolkit / `libnvvm` licence permits redistribution on CE's
infrastructure (NVIDIA's EULA generally allows this for development tools).

## Compilation pipeline

For reference, the full pipeline that the wrapper reproduces:

```
User's .rs file
|
v
[cargo build]
| --target=nvptx64-nvidia-cuda
| -Zbuild-std=core,alloc
| CARGO_ENCODED_RUSTFLAGS with -Zcodegen-backend=...
v
[rustc + rustc_codegen_nvvm]
| Compiles Rust -> NVVM IR (LLVM 7 bitcode dialect)
v
[libnvvm] (from CUDA toolkit)
| Optimises NVVM IR -> PTX
v
.ptx file (stdout)
```
129 changes: 129 additions & 0 deletions contrib/godbolt/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#!/usr/bin/env bash
#
# install.sh - Install the rust-cuda toolchain for Compiler Explorer.
#
# This script is meant to be run on a CE builder node (or locally for
# testing). It performs the following:
#
# 1. Installs the pinned Rust nightly with required components.
# 2. Clones the rust-cuda repository (or uses a local checkout).
# 3. Builds the rustc_codegen_nvvm codegen backend against libnvvm.
# 4. Copies the backend, cuda_std sources, and the wrapper script into
# a self-contained prefix under /opt/compiler-explorer/rust-cuda/.
#
# Prerequisites:
# - CUDA toolkit installed (CUDA_PATH or /usr/local/cuda)
# - cmake, ninja-build, clang, pkg-config, libssl-dev, zlib1g-dev
# - For LLVM 7 path: the prebuilt LLVM archive is downloaded automatically
# by the codegen's build.rs, or you can pre-install LLVM 7 and export
# LLVM_CONFIG=/path/to/llvm-config-7.
#
# Environment variables:
# INSTALL_PREFIX - Where to install (default: /opt/compiler-explorer/rust-cuda)
# CUDA_PATH - CUDA toolkit root (default: /usr/local/cuda)
# RUST_CUDA_REPO - Path to an existing rust-cuda checkout (skips git clone)
# RUST_CUDA_REF - Git ref to check out (default: main)

set -euo pipefail

INSTALL_PREFIX="${INSTALL_PREFIX:-/opt/compiler-explorer/rust-cuda}"
CUDA_PATH="${CUDA_PATH:-/usr/local/cuda}"
RUST_CUDA_REF="${RUST_CUDA_REF:-main}"

NIGHTLY="nightly-2026-04-02"
COMPONENTS="rust-src,rustc-dev,llvm-tools-preview"

echo "==> rust-cuda Compiler Explorer installer"
echo " prefix: ${INSTALL_PREFIX}"
echo " CUDA: ${CUDA_PATH}"
echo " nightly: ${NIGHTLY}"

# ---------------------------------------------------------------------------
# 1. Install the pinned Rust nightly
# ---------------------------------------------------------------------------
echo "==> Installing Rust ${NIGHTLY} ..."
if ! command -v rustup &>/dev/null; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain none
export PATH="${HOME}/.cargo/bin:${PATH}"
fi

rustup toolchain install "${NIGHTLY}" --component "${COMPONENTS}"
rustup default "${NIGHTLY}"

echo " rustc: $(rustc --version)"

# ---------------------------------------------------------------------------
# 2. Get the rust-cuda source
# ---------------------------------------------------------------------------
if [[ -n "${RUST_CUDA_REPO:-}" ]]; then
REPO_DIR="${RUST_CUDA_REPO}"
echo "==> Using existing checkout at ${REPO_DIR}"
else
REPO_DIR="$(mktemp -d -t rust-cuda-src.XXXXXXXXXX)"
echo "==> Cloning rust-cuda (ref: ${RUST_CUDA_REF}) into ${REPO_DIR} ..."
git clone --depth 1 --branch "${RUST_CUDA_REF}" \
https://github.com/Rust-GPU/rust-cuda.git "${REPO_DIR}"
fi

# ---------------------------------------------------------------------------
# 3. Build the codegen backend
# ---------------------------------------------------------------------------
echo "==> Building rustc_codegen_nvvm ..."
export LD_LIBRARY_PATH="${CUDA_PATH}/nvvm/lib64:${CUDA_PATH}/lib64:${LD_LIBRARY_PATH:-}"

cd "${REPO_DIR}"
cargo build -p rustc_codegen_nvvm --release

# Find the built .so
CODEGEN_SO="$(find target/release -maxdepth 2 -name 'librustc_codegen_nvvm.so' -print -quit 2>/dev/null || true)"
if [[ -z "${CODEGEN_SO}" ]]; then
# Try the deps directory with hash suffix.
CODEGEN_SO="$(find target/release/deps -maxdepth 1 -name 'librustc_codegen_nvvm-*.so' -print -quit 2>/dev/null || true)"
fi
if [[ -z "${CODEGEN_SO}" ]]; then
echo "error: could not find librustc_codegen_nvvm.so after build" >&2
exit 1
fi
echo " codegen backend: ${CODEGEN_SO}"

# ---------------------------------------------------------------------------
# 4. Install into the prefix
# ---------------------------------------------------------------------------
echo "==> Installing to ${INSTALL_PREFIX} ..."
mkdir -p "${INSTALL_PREFIX}"/{bin,lib,crates}

# Backend shared library.
cp "${CODEGEN_SO}" "${INSTALL_PREFIX}/lib/librustc_codegen_nvvm.so"

# Copy the crates that kernel code depends on at build time.
for crate in cuda_std cuda_std_macros; do
cp -a "${REPO_DIR}/crates/${crate}" "${INSTALL_PREFIX}/crates/${crate}"
done

# Copy workspace-level files needed by cargo (Cargo.lock is especially
# important so dependency resolution is reproducible).
cp "${REPO_DIR}/Cargo.lock" "${INSTALL_PREFIX}/" 2>/dev/null || true

# Build and install the wrapper binary.
(
cd "${REPO_DIR}/contrib/godbolt/rust-cuda-wrapper"
cargo build --release
)
cp "${REPO_DIR}/contrib/godbolt/rust-cuda-wrapper/target/release/rust-cuda-wrapper" \
"${INSTALL_PREFIX}/bin/"
chmod +x "${INSTALL_PREFIX}/bin/rust-cuda-wrapper"

# Version marker.
echo "${NIGHTLY}" > "${INSTALL_PREFIX}/rust-toolchain-version"

# Also copy any native libs the codegen may need at link time (from the
# same build directory).
for lib in "${REPO_DIR}"/target/release/deps/lib*.so; do
[[ -f "${lib}" ]] && cp "${lib}" "${INSTALL_PREFIX}/lib/" 2>/dev/null || true
done

echo "==> Installation complete."
echo ""
echo "Test with:"
echo " RUST_CUDA_ROOT=${INSTALL_PREFIX} CUDA_PATH=${CUDA_PATH} \\"
echo " ${INSTALL_PREFIX}/bin/rust-cuda-wrapper contrib/godbolt/test-kernel.rs"
1 change: 1 addition & 0 deletions contrib/godbolt/rust-cuda-wrapper/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
Loading
Loading