Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
119 changes: 119 additions & 0 deletions contrib/godbolt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# 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 wrapper
script 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.sh` | The wrapper script 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 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:
./contrib/godbolt/rust-cuda-wrapper.sh 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 lib/librustc_codegen_nvvm.so exists at that path, or adjust
# CODEGEN_SO in the script.
```

## 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)
```
124 changes: 124 additions & 0 deletions contrib/godbolt/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/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

# The wrapper script.
cp "${REPO_DIR}/contrib/godbolt/rust-cuda-wrapper.sh" "${INSTALL_PREFIX}/bin/"
chmod +x "${INSTALL_PREFIX}/bin/rust-cuda-wrapper.sh"

# 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.sh contrib/godbolt/test-kernel.rs"
Loading
Loading