Skip to content

Commit 65a20a9

Browse files
committed
Add compiletests
These tests check that code compiles (or doesn't) as expected. The framework also has the capability to check the generated ptx (see the tests in `dis/`. These tests are not run, so they do not validate runtime behavior. This also means they can run on machines without a GPU, like GitHub Actions runners. This is largely modeled / structured after rust-gpu's compiletests in anticipation of a project merge one day.
1 parent aa7e615 commit 65a20a9

30 files changed

+1703
-8
lines changed

.cargo/config.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
[alias]
22
xtask = "run -p xtask --bin xtask --"
3+
compiletest = "run --release -p compiletests --"

.github/workflows/ci_linux.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,18 @@ jobs:
153153
MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }}
154154
run: |
155155
echo "Stubbed out"
156+
compiletest:
157+
name: Compile tests
158+
runs-on: ubuntu-latest
159+
container:
160+
image: "ghcr.io/rust-gpu/rust-cuda-ubuntu24-cuda12:latest"
161+
steps:
162+
- name: Checkout repository
163+
uses: actions/checkout@v4
164+
- name: Run cargo version
165+
run: cargo --version
166+
- name: Rustfmt compiletests
167+
shell: bash
168+
run: shopt -s globstar && rustfmt --check tests/compiletests/ui/**/*.rs
169+
- name: Compiletest
170+
run: cargo run -p compiletests --release --no-default-features -- --target-arch compute_61,compute_70,compute_90

.github/workflows/ci_windows.yml

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,18 @@ jobs:
2626
target: x86_64-pc-windows-msvc
2727
cuda: "12.8.1"
2828
linux-local-args: []
29-
sub-packages: ["nvcc", "nvrtc", "nvrtc_dev", "cuda_profiler_api", "cudart", "cublas", "cublas_dev", "curand", "curand_dev"]
29+
sub-packages:
30+
[
31+
"nvcc",
32+
"nvrtc",
33+
"nvrtc_dev",
34+
"cuda_profiler_api",
35+
"cudart",
36+
"cublas",
37+
"cublas_dev",
38+
"curand",
39+
"curand_dev",
40+
]
3041

3142
steps:
3243
- name: Checkout repository
@@ -41,7 +52,7 @@ jobs:
4152
linux-local-args: ${{ toJson(matrix.linux-local-args) }}
4253
use-local-cache: false
4354
sub-packages: ${{ toJson(matrix.sub-packages) }}
44-
log-file-suffix: '${{matrix.os}}-${{matrix.cuda}}'
55+
log-file-suffix: "${{matrix.os}}-${{matrix.cuda}}"
4556

4657
- name: Verify CUDA installation
4758
run: nvcc --version
@@ -76,3 +87,6 @@ jobs:
7687
env:
7788
RUSTDOCFLAGS: -Dwarnings
7889
run: cargo doc --workspace --all-features --document-private-items --no-deps --exclude "optix*" --exclude "path-tracer" --exclude "denoiser" --exclude "vecadd*" --exclude "gemm*" --exclude "ex*" --exclude "cudnn*" --exclude "cust_raw"
90+
# Disabled due to dll issues, someone with Windows knowledge needed
91+
# - name: Compiletest
92+
# run: cargo run -p compiletests --release --no-default-features -- --target-arch compute_61,compute_70,compute_90

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ members = [
1616
"examples/cuda/path_tracer/kernels",
1717

1818
"examples/optix/*",
19+
"tests/compiletests",
20+
"tests/compiletests/deps-helper",
1921
]
2022

2123
exclude = [
@@ -24,3 +26,7 @@ exclude = [
2426

2527
[profile.dev.package.rustc_codegen_nvvm]
2628
opt-level = 3
29+
30+
[workspace.dependencies]
31+
cuda_std = { path = "crates/cuda_std" }
32+
cuda_builder = { path = "crates/cuda_builder" }

crates/rustc_codegen_nvvm/src/context.rs

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -551,35 +551,81 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
551551
}
552552
}
553553

554+
#[derive(Clone)]
555+
pub enum DisassembleMode {
556+
All,
557+
Function(String),
558+
Entry(String),
559+
Globals,
560+
}
561+
554562
#[derive(Default, Clone)]
555563
pub struct CodegenArgs {
556564
pub nvvm_options: Vec<NvvmOption>,
557565
pub override_libm: bool,
558566
pub use_constant_memory_space: bool,
559567
pub final_module_path: Option<PathBuf>,
568+
pub disassemble: Option<DisassembleMode>,
560569
}
561570

562571
impl CodegenArgs {
563572
pub fn from_session(sess: &Session) -> Self {
564-
Self::parse(&sess.opts.cg.llvm_args)
573+
Self::parse(&sess.opts.cg.llvm_args, sess)
565574
}
566575

567576
// we may want to use rustc's own option parsing facilities to have better errors in the future.
568-
pub fn parse(args: &[String]) -> Self {
577+
pub fn parse(args: &[String], sess: &Session) -> Self {
569578
// TODO: replace this with a "proper" arg parser.
570579
let mut cg_args = Self::default();
571580

581+
let mut skip_next = false;
572582
for (idx, arg) in args.iter().enumerate() {
583+
if skip_next {
584+
skip_next = false;
585+
continue;
586+
}
587+
573588
if let Ok(flag) = NvvmOption::from_str(arg) {
574589
cg_args.nvvm_options.push(flag);
575590
} else if arg == "--override-libm" {
576591
cg_args.override_libm = true;
577592
} else if arg == "--use-constant-memory-space" {
578593
cg_args.use_constant_memory_space = true;
579594
} else if arg == "--final-module-path" {
580-
cg_args.final_module_path = Some(PathBuf::from(
581-
args.get(idx + 1).expect("No path for --final-module-path"),
582-
));
595+
let path = match args.get(idx + 1) {
596+
Some(p) => p,
597+
None => sess
598+
.dcx()
599+
.fatal("--final-module-path requires a path argument"),
600+
};
601+
cg_args.final_module_path = Some(PathBuf::from(path));
602+
skip_next = true;
603+
} else if arg == "--disassemble" {
604+
cg_args.disassemble = Some(DisassembleMode::All);
605+
} else if arg == "--disassemble-globals" {
606+
cg_args.disassemble = Some(DisassembleMode::Globals);
607+
} else if arg == "--disassemble-fn" {
608+
let func_name = match args.get(idx + 1) {
609+
Some(name) => name.clone(),
610+
None => sess
611+
.dcx()
612+
.fatal("--disassemble-fn requires a function name argument"),
613+
};
614+
cg_args.disassemble = Some(DisassembleMode::Function(func_name));
615+
skip_next = true;
616+
} else if let Some(func) = arg.strip_prefix("--disassemble-fn=") {
617+
cg_args.disassemble = Some(DisassembleMode::Function(func.to_string()));
618+
} else if arg == "--disassemble-entry" {
619+
let entry_name = match args.get(idx + 1) {
620+
Some(name) => name.clone(),
621+
None => sess
622+
.dcx()
623+
.fatal("--disassemble-entry requires an entry name argument"),
624+
};
625+
cg_args.disassemble = Some(DisassembleMode::Entry(entry_name));
626+
skip_next = true;
627+
} else if let Some(entry) = arg.strip_prefix("--disassemble-entry=") {
628+
cg_args.disassemble = Some(DisassembleMode::Entry(entry.to_string()));
583629
}
584630
}
585631

crates/rustc_codegen_nvvm/src/lib.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ mod lto;
5252
mod mono_item;
5353
mod nvvm;
5454
mod override_fns;
55+
mod ptx_filter;
5556
mod target;
5657
mod ty;
5758

@@ -216,14 +217,30 @@ impl CodegenBackend for NvvmCodegenBackend {
216217
let cmdline = sess.opts.cg.target_feature.split(',');
217218
let cfg = sess.target.options.features.split(',');
218219

219-
let target_features: Vec<_> = cfg
220+
let mut target_features: Vec<_> = cfg
220221
.chain(cmdline)
221222
.filter(|l| l.starts_with('+'))
222223
.map(|l| &l[1..])
223224
.filter(|l| !l.is_empty())
224225
.map(rustc_span::Symbol::intern)
225226
.collect();
226227

228+
// Add backend-synthesized features (e.g., hierarchical compute capabilities)
229+
// Parse CodegenArgs to get the architecture from llvm-args
230+
let args = context::CodegenArgs::from_session(sess);
231+
for opt in &args.nvvm_options {
232+
if let ::nvvm::NvvmOption::Arch(arch) = opt {
233+
// Add all features up to and including the current architecture
234+
let backend_features = arch.all_target_features();
235+
target_features.extend(
236+
backend_features
237+
.iter()
238+
.map(|f| rustc_span::Symbol::intern(f)),
239+
);
240+
break;
241+
}
242+
}
243+
227244
// For NVPTX, all target features are stable
228245
let unstable_target_features = target_features.clone();
229246

crates/rustc_codegen_nvvm/src/link.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use tracing::{debug, trace};
3030

3131
use crate::LlvmMod;
3232
use crate::context::CodegenArgs;
33+
use crate::ptx_filter::{PtxFilter, PtxFilterConfig};
3334

3435
pub(crate) struct NvvmMetadataLoader;
3536

@@ -305,6 +306,31 @@ fn codegen_into_ptx_file(
305306
}
306307
};
307308

309+
// If disassembly is requested, print PTX to stderr
310+
if args.disassemble.is_some()
311+
&& let Ok(ptx_str) = std::str::from_utf8(&ptx_bytes)
312+
{
313+
let config = PtxFilterConfig::from_codegen_args(&args);
314+
let filter = PtxFilter::new(config);
315+
let output = filter.filter(ptx_str);
316+
if !output.is_empty() {
317+
// Check if we're in JSON mode by checking the error format
318+
use rustc_session::config::ErrorOutputType;
319+
match sess.opts.error_format {
320+
ErrorOutputType::Json { .. } => {
321+
sess.dcx()
322+
.err("PTX disassembly output in JSON mode is not supported");
323+
}
324+
_ => {
325+
// In normal mode, just print to stderr
326+
// Replace tabs with spaces for cleaner output
327+
let output = output.replace('\t', " ");
328+
eprintln!("{output}");
329+
}
330+
}
331+
}
332+
}
333+
308334
std::fs::write(out_filename, ptx_bytes)
309335
}
310336

0 commit comments

Comments
 (0)