From e083b8bbc06e491065726bdee69c2ab651bc4689 Mon Sep 17 00:00:00 2001 From: sgasho Date: Sat, 24 Oct 2026 06:46:18 +0000 Subject: [PATCH 1/4] offload: pass the linked device image to the host pass --- compiler/rustc_codegen_llvm/src/back/write.rs | 14 +- .../rustc_codegen_llvm/src/diagnostics.rs | 10 +- .../src/llvm/offload_ffi.rs | 24 +-- .../llvm-wrapper/offload/OffloadWrapper.cpp | 195 ++++-------------- tests/ui/offload/check_config.fail.stderr | 2 +- tests/ui/offload/check_config.rs | 2 +- 6 files changed, 69 insertions(+), 178 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index b8237443cccc3..01380b3f6810f 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -822,8 +822,9 @@ pub(crate) unsafe fn llvm_optimize<'ll>( }; // This assumes that we previously compiled our kernels for a gpu target, which created a - // `.bc` artifact. The user is supposed to provide us with a path to this artifact, we - // don't need any other artifacts from the previous run. + // `.ptx` (NVPTX) or `.elf` (AMDGPU) artifact. + // The user is supposed to provide us with a path to this artifact, + // we don't need any other artifacts from the previous run. if !cgcx.target_is_like_gpu && is_final_stage { if let Some(device_path) = config .offload @@ -833,15 +834,18 @@ pub(crate) unsafe fn llvm_optimize<'ll>( let device_pathbuf = PathBuf::from(device_path); if device_pathbuf.is_relative() { dcx.emit_err(crate::diagnostics::OffloadWithoutAbsPath); - } else if device_pathbuf.extension().and_then(|e| e.to_str()) != Some("bc") { + } else if !matches!( + device_pathbuf.extension().and_then(|e| e.to_str()), + Some("ptx" | "elf") + ) { dcx.emit_err(crate::diagnostics::OffloadWrongFileName); } else if !device_pathbuf.exists() { dcx.emit_err(crate::diagnostics::OffloadNonexistingPath); } - let device_bitcode_c = path_to_c_string(device_pathbuf.as_path()); + let device_image_c = path_to_c_string(device_pathbuf.as_path()); let ok = unsafe { llvm::RustOffloadWrapper::get_instance() - .llvm_rust_offload_wrap_images(llmod, device_bitcode_c.as_c_str()) + .llvm_rust_offload_wrap_images(llmod, device_image_c.as_c_str()) }; if !ok { dcx.emit_err(crate::diagnostics::OffloadWrapImagesFailed); diff --git a/compiler/rustc_codegen_llvm/src/diagnostics.rs b/compiler/rustc_codegen_llvm/src/diagnostics.rs index 094b683ded56b..19b2f68107e6c 100644 --- a/compiler/rustc_codegen_llvm/src/diagnostics.rs +++ b/compiler/rustc_codegen_llvm/src/diagnostics.rs @@ -73,7 +73,7 @@ pub(crate) struct RustOffloadComponentMissing { #[derive(Diagnostic)] #[diag( - "using the offload feature requires -Z offload=.bc>" + "using the offload feature requires -Z offload=.ptx or .elf>" )] pub(crate) struct OffloadWithoutEnable; @@ -82,18 +82,20 @@ pub(crate) struct OffloadWithoutEnable; pub(crate) struct OffloadWithoutFatLTO; #[derive(Diagnostic)] -#[diag("using the `-Z offload=Host=/absolute/path/to/.bc` flag requires an absolute path")] +#[diag( + "using the `-Z offload=Host=/absolute/path/to/.ptx` or `.elf` flag requires an absolute path" +)] pub(crate) struct OffloadWithoutAbsPath; #[derive(Diagnostic)] #[diag( - "using the `-Z offload=Host=/absolute/path/to/.bc` flag must point to a .bc file produced by the device compilation (--emit=llvm-bc)" + "using the `-Z offload=Host=/absolute/path/to/.ptx` or `.elf` flag must point to a .ptx or .elf file produced by the device compilation" )] pub(crate) struct OffloadWrongFileName; #[derive(Diagnostic)] #[diag( - "the given path/file to `.bc` does not exist. Did you forget to run the device compilation first?" + "the given path/file to `.ptx` or `.elf` does not exist. Did you forget to run the device compilation first?" )] pub(crate) struct OffloadNonexistingPath; diff --git a/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs index 60e0836a35d88..4f2369aef0d53 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs @@ -6,9 +6,8 @@ use super::ffi::{Module, Value}; type LLVMRustOffloadMapperFn = unsafe extern "C" fn(&Value, &Value, *const &Value); type LLVMRustOffloadWrapImagesFn = - for<'ll> unsafe extern "C" fn(Module<'ll>, *const c_char, *const c_char) -> bool; + for<'ll> unsafe extern "C" fn(Module<'ll>, *const c_char) -> bool; -use rustc_fs_util::path_to_c_string; use rustc_session::config::host_tuple; use rustc_session::filesearch; @@ -17,7 +16,6 @@ use crate::llvm; pub(crate) struct RustOffloadWrapper { LLVMRustOffloadMapper: LLVMRustOffloadMapperFn, LLVMRustOffloadWrapImages: LLVMRustOffloadWrapImagesFn, - lld_path: Option, // Keep the dynamic library loaded while the function pointers are used. _lib: libloading::Library, } @@ -59,18 +57,15 @@ impl RustOffloadWrapper { pub(crate) unsafe fn llvm_rust_offload_wrap_images<'ll>( &self, host_m: Module<'ll>, - device_bitcode_path: &CStr, + device_image_path: &CStr, ) -> bool { - let lld_c = self.lld_path.as_deref().map(path_to_c_string).unwrap_or_default(); - unsafe { - (self.LLVMRustOffloadWrapImages)(host_m, lld_c.as_ptr(), device_bitcode_path.as_ptr()) - } + unsafe { (self.LLVMRustOffloadWrapImages)(host_m, device_image_path.as_ptr()) } } fn call_dynamic( sysroot: &rustc_session::config::Sysroot, ) -> Result { - let (rust_offload_path, lld_path) = Self::get_offload_and_lld_paths(sysroot)?; + let rust_offload_path = Self::get_offload_path(sysroot)?; let lib = unsafe { libloading::Library::new(rust_offload_path)? }; let llvm_rust_offload_wrapper = @@ -81,14 +76,13 @@ impl RustOffloadWrapper { Ok(Self { LLVMRustOffloadMapper: llvm_rust_offload_wrapper, LLVMRustOffloadWrapImages: llvm_rust_offload_wrap_images, - lld_path, _lib: lib, }) } - fn get_offload_and_lld_paths( + fn get_offload_path( sysroot: &rustc_session::config::Sysroot, - ) -> Result<(PathBuf, Option), RustOffloadLibraryError> { + ) -> Result { let llvm_version_major = llvm::LLVMRustVersionMajor(); let mut searched = Vec::new(); @@ -102,11 +96,7 @@ impl RustOffloadWrapper { continue; } - let lld_path = filesearch::make_target_bin_path(root, host_tuple()) - .join(format!("rust-lld{}", std::env::consts::EXE_SUFFIX)); - let lld_path = lld_path.is_file().then_some(lld_path); - - return Ok((rust_offload_path, lld_path)); + return Ok(rust_offload_path); } Err(RustOffloadLibraryError::NotFound { diff --git a/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp index 5c0fabb3fcee8..6a51e58f896be 100644 --- a/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp @@ -1,29 +1,22 @@ #include "../SuppressLLVMWarnings.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Bitcode/BitcodeReader.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Frontend/Offloading/OffloadWrapper.h" #include "llvm/Frontend/Offloading/Utility.h" #include "llvm/IR/IRBuilder.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" -#include "llvm/MC/TargetRegistry.h" -#include "llvm/Support/CodeGen.h" #include "llvm/Support/Error.h" -#include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MemoryBufferRef.h" +#include "llvm/Support/Path.h" #include "llvm/Support/Program.h" +#include "llvm/Support/Regex.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" -#include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/ValueMapper.h" @@ -34,18 +27,6 @@ using namespace llvm; -static Error writeFile(StringRef Filename, StringRef Data) { - Expected> OutputOrErr = - FileOutputBuffer::create(Filename, Data.size()); - if (!OutputOrErr) - return OutputOrErr.takeError(); - std::unique_ptr Output = std::move(*OutputOrErr); - llvm::copy(Data, Output->getBufferStart()); - if (Error E = Output->commit()) - return E; - return Error::success(); -} - // Clone OldFn into NewFn, remapping its arguments to RebuiltArgs. // Each arg of OldFn is replaced with the corresponding value in RebuiltArgs. // For scalars, RebuiltArgs contains the value cast and/or truncated to the @@ -96,37 +77,44 @@ static bool reportAndFailWrappingImages(Error E, const char *What) { return false; } +/// Returns the target architecture (e.g. "sm_86") named by the `.target` +/// directive of the given PTX text. The result points into `PtxBuf`. +static Expected getPtxArch(MemoryBufferRef PtxBuf) { + const Regex TargetRe("^\\.target[[:space:]]+([^,[:space:]]+)", + Regex::Newline); + + SmallVector M; + if (!TargetRe.match(PtxBuf.getBuffer(), &M)) + return createStringError("no .target directive in %s", + PtxBuf.getBufferIdentifier().str().c_str()); + + return M[1]; +} + static Expected> -assembleWithPtxas(StringRef Ptx, StringRef Arch) { +assembleWithPtxas(MemoryBufferRef PtxBuf) { + Expected ArchOrErr = getPtxArch(PtxBuf); + if (!ArchOrErr) + return ArchOrErr.takeError(); + const ErrorOr Ptxas = sys::findProgramByName("ptxas"); if (!Ptxas) return createStringError(Ptxas.getError(), "ptxas not found in PATH"); - SmallString<128> PtxFilePath; - if (std::error_code E = - sys::fs::createTemporaryFile("rust-offload", "ptx", PtxFilePath)) - return errorCodeToError(E); - SmallString<128> CubinFilePath; if (std::error_code E = sys::fs::createTemporaryFile("rust-offload", "cubin", CubinFilePath)) return errorCodeToError(E); auto Cleanup = scope_exit([&] { - if (std::error_code E = sys::fs::remove(PtxFilePath)) - (void)reportAndFailWrappingImages( - errorCodeToError(E), "assembleWithPtxas: PtxFilePath cleanup"); if (std::error_code E = sys::fs::remove(CubinFilePath)) (void)reportAndFailWrappingImages( errorCodeToError(E), "assembleWithPtxas: CubinFilePath cleanup"); }); - if (Error E = writeFile(PtxFilePath, Ptx)) - return std::move(E); - const StringRef Args[] = { - *Ptxas, "-m64", "-O3", "--gpu-name", - Arch, "--output-file", CubinFilePath, PtxFilePath, + *Ptxas, "-m64", "-O3", "--gpu-name", + *ArchOrErr, "--output-file", CubinFilePath, PtxBuf.getBufferIdentifier(), }; std::string ErrorMsg; @@ -145,130 +133,37 @@ assembleWithPtxas(StringRef Ptx, StringRef Arch) { return std::move(*CubinOrError); } -static Expected> -linkWithRustLld(StringRef Obj, StringRef LldPath) { - SmallString<128> ObjFilePath; - if (std::error_code E = - sys::fs::createTemporaryFile("rust-offload", "o", ObjFilePath)) - return errorCodeToError(E); - - SmallString<128> SoFilePath; - if (std::error_code E = - sys::fs::createTemporaryFile("rust-offload", "so", SoFilePath)) - return errorCodeToError(E); - - auto Cleanup = scope_exit([&] { - if (std::error_code E = sys::fs::remove(ObjFilePath)) - (void)reportAndFailWrappingImages(errorCodeToError(E), - "linkWithRustLld: ObjFilePath cleanup"); - if (std::error_code E = sys::fs::remove(SoFilePath)) - (void)reportAndFailWrappingImages(errorCodeToError(E), - "linkWithRustLld: SoFilePath cleanup"); - }); - - if (Error E = writeFile(ObjFilePath, Obj)) - return std::move(E); - - const StringRef Args[] = { - LldPath, "-flavor", "gnu", "-shared", - "--no-undefined", "-o", SoFilePath, ObjFilePath, - }; - - std::string ErrorMsg; - const int Status = - sys::ExecuteAndWait(LldPath, Args, std::nullopt, {}, 0, 0, &ErrorMsg); - - if (Status != 0) - return createStringError("linkWithRustLld: status %d: %s", Status, - ErrorMsg.c_str()); - - ErrorOr> ElfOrError = - MemoryBuffer::getFileAsStream(SoFilePath); - if (!ElfOrError) - return errorCodeToError(ElfOrError.getError()); - - return std::move(*ElfOrError); -} - -static Expected> -compileDeviceImage(MemoryBufferRef Input, const char *LldPath) { - LLVMContext Ctx; - Expected> ModOrErr = parseBitcodeFile(Input, Ctx); - if (!ModOrErr) - return ModOrErr.takeError(); - Module &M = **ModOrErr; - - const Triple &DeviceTriple = M.getTargetTriple(); - StringRef Arch; - for (Function &F : M) - if (F.hasFnAttribute("target-cpu")) { - Arch = F.getFnAttribute("target-cpu").getValueAsString(); - break; - } - - if (Arch.empty()) - return createStringError("no target-cpu attribute in device bitcode"); - - std::string ErrorMsg; - const Target *DeviceTarget = - TargetRegistry::lookupTarget(DeviceTriple, ErrorMsg); - if (!DeviceTarget) - return createStringError(ErrorMsg); - - std::unique_ptr TM(DeviceTarget->createTargetMachine( - DeviceTriple, Arch, /*Features=*/"", TargetOptions(), Reloc::PIC_)); - if (!TM) - return createStringError("createTargetMachine failed for %s", - DeviceTriple.str().c_str()); - - const bool IsNvptx = DeviceTriple.isNVPTX(); - - legacy::PassManager PM; - SmallString<0> Emitted; - raw_svector_ostream OS(Emitted); - const CodeGenFileType FileType = - IsNvptx ? CodeGenFileType::AssemblyFile : CodeGenFileType::ObjectFile; - if (TM->addPassesToEmitFile(PM, OS, nullptr, FileType)) - return createStringError("target %s cannot emit %s", - DeviceTriple.str().c_str(), - IsNvptx ? "assembly" : "object"); - - PM.run(**ModOrErr); - - if (IsNvptx) - return assembleWithPtxas(Emitted, Arch); - if (DeviceTriple.isAMDGPU()) { - if (!LldPath || !*LldPath) - return createStringError("rust-lld path was not provided for %s", - DeviceTriple.str().c_str()); - return linkWithRustLld(Emitted, LldPath); - } - - return createStringError("unsupported offload target %s", - DeviceTriple.str().c_str()); -} - extern "C" bool LLVMRustOffloadWrapImages(LLVMModuleRef HostMRef, - const char *LldPath, - const char *DeviceBitcodePath) { + const char *DeviceImagePath) { Module &M = *unwrap(HostMRef); if (!hasOffloadEntries(M)) return true; ErrorOr> BufOrErr = - MemoryBuffer::getFile(DeviceBitcodePath); + MemoryBuffer::getFile(DeviceImagePath); if (std::error_code EC = BufOrErr.getError()) - return reportAndFailWrappingImages(createFileError(DeviceBitcodePath, EC), - "device bitcode"); + return reportAndFailWrappingImages(createFileError(DeviceImagePath, EC), + "device image"); std::unique_ptr Buf = std::move(*BufOrErr); - Expected> ImageOrErr = - compileDeviceImage(Buf->getMemBufferRef(), LldPath); - if (!ImageOrErr) - return reportAndFailWrappingImages(ImageOrErr.takeError(), - "device compile"); + std::unique_ptr DeviceImage; + StringRef Ext = sys::path::extension(DeviceImagePath); + if (Ext == ".ptx") { + Expected> CubinOrErr = + assembleWithPtxas(Buf->getMemBufferRef()); + if (!CubinOrErr) + return reportAndFailWrappingImages(CubinOrErr.takeError(), "ptxas"); + DeviceImage = std::move(*CubinOrErr); + } else if (Ext == ".elf") { + DeviceImage = std::move(Buf); + } else { + return reportAndFailWrappingImages( + createStringError("unsupported device image %s: expected .ptx or .elf", + DeviceImagePath), + "device image path"); + } - StringRef ImageBuf = (*ImageOrErr)->getBuffer(); + StringRef ImageBuf = DeviceImage->getBuffer(); ArrayRef Image(ImageBuf.data(), ImageBuf.size()); if (Error E = offloading::wrapOpenMPBinaries( diff --git a/tests/ui/offload/check_config.fail.stderr b/tests/ui/offload/check_config.fail.stderr index 87df9d42bafd1..6f4ae31491d86 100644 --- a/tests/ui/offload/check_config.fail.stderr +++ b/tests/ui/offload/check_config.fail.stderr @@ -1,4 +1,4 @@ -error: using the offload feature requires -Z offload=.bc> +error: using the offload feature requires -Z offload=.ptx or .elf> error: using the offload feature requires -C lto=fat diff --git a/tests/ui/offload/check_config.rs b/tests/ui/offload/check_config.rs index 9865d36049a8f..d28d27d2c9d10 100644 --- a/tests/ui/offload/check_config.rs +++ b/tests/ui/offload/check_config.rs @@ -6,7 +6,7 @@ //@[pass] compile-flags: -Zunstable-options -Zoffload=Device -Clto=fat --emit=metadata //@[fail] compile-flags: -Clto=thin -//[fail]~? ERROR: using the offload feature requires -Z offload=.bc> +//[fail]~? ERROR: using the offload feature requires -Z offload=.ptx or .elf> //[fail]~? ERROR: using the offload feature requires -C lto=fat #![feature(gpu_offload)] From b76246de20a0840d70d367561eb5680f249fc757 Mon Sep 17 00:00:00 2001 From: sgasho Date: Sun, 25 Oct 2026 08:17:22 +0000 Subject: [PATCH 2/4] offload: make the device build work without `--emit=llvm-bc`/`llvm-ir` --- compiler/rustc_codegen_llvm/src/back/write.rs | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 01380b3f6810f..7e71755ed4e70 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -657,22 +657,17 @@ pub(crate) unsafe fn llvm_optimize<'ll>( None }; - fn handle_offload<'ll>(cx: &SimpleCx<'ll>, old_fn: &'ll llvm::Value) { + // Wraps `old_fn` into a new kernel that takes the implicit `dyn_ptr` as its first argument. + // Returns the new function, or `None` if nothing was wrapped + fn handle_offload<'ll>( + cx: &SimpleCx<'ll>, + old_fn: &'ll llvm::Value, + ) -> Option<&'ll llvm::Value> { let old_fn_ty = cx.get_type_of_global(old_fn); let old_param_types = cx.func_params_types(old_fn_ty); let old_param_count = old_param_types.len(); if old_param_count == 0 { - return; - } - - let first_param = llvm::get_param(old_fn, 0); - let c_name = llvm::get_value_name(first_param); - let first_arg_name = str::from_utf8(&c_name).unwrap(); - // We might call llvm_optimize (and thus this code) multiple times on the same IR, - // but we shouldn't add this helper ptr multiple times. - // FIXME(offload): This could break if the user calls his first argument `dyn_ptr`. - if first_arg_name == "dyn_ptr" { - return; + return None; } // Create the new parameter list, with ptr as the first argument @@ -747,6 +742,7 @@ pub(crate) unsafe fn llvm_optimize<'ll>( } // Now we can re-use the old name, without name collision. llvm::set_value_name(new_fn, &name); + Some(new_fn) } if cgcx.target_is_like_gpu @@ -755,10 +751,13 @@ pub(crate) unsafe fn llvm_optimize<'ll>( let cx = SimpleCx::new(llmod, llcx, cgcx.pointer_size); for func in cx.get_functions() { let offload_kernel = "offload-kernel"; - if attributes::has_string_attr(func, offload_kernel) { - handle_offload(&cx, func); + if !attributes::has_string_attr(func, offload_kernel) { + continue; + } + match handle_offload(&cx, func) { + Some(new_fn) => attributes::remove_string_attr_from_llfn(new_fn, offload_kernel), + None => attributes::remove_string_attr_from_llfn(func, offload_kernel), } - attributes::remove_string_attr_from_llfn(func, offload_kernel); } } From c6749d8027e05f8a39609e5cec386f872b5a1da1 Mon Sep 17 00:00:00 2001 From: sgasho Date: Thu, 29 Oct 2026 15:27:50 +0000 Subject: [PATCH 3/4] offload: build bin crates as cdylib on the device side --- compiler/rustc_interface/src/passes.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 7df2ede5053b2..6dc3f74f054f1 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -36,7 +36,7 @@ use rustc_parse::lexer::StripTokens; use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_passes::{abi_test, input_stats, layout_test}; use rustc_resolve::{Resolver, ResolverOutputs}; -use rustc_session::config::{Input, OutFileName, OutputFilenames, OutputType}; +use rustc_session::config::{Input, Offload, OutFileName, OutputFilenames, OutputType}; use rustc_session::diagnostics::feature_err; use rustc_session::output::{filename_for_input, invalid_output_for_target}; use rustc_session::search_paths::PathKind; @@ -1485,6 +1485,16 @@ pub fn collect_crate_types( } } + // GPU code is never run as a binary; the offload runtime looks up kernels by + // name, and only cdylibs export their symbols. + if session.opts.unstable_opts.offload.iter().any(|o| matches!(o, Offload::Device(_))) { + for crate_type in &mut base { + if *crate_type == CrateType::Executable { + *crate_type = CrateType::Cdylib; + } + } + } + base.retain(|crate_type| { if invalid_output_for_target(session, *crate_type) { session.dcx().emit_warn(diagnostics::UnsupportedCrateTypeForTarget { From 663a4bab15967278335ade9918c89c6654e4bdf1 Mon Sep 17 00:00:00 2001 From: sgasho Date: Wed, 4 Nov 2026 13:10:47 +0000 Subject: [PATCH 4/4] add needs-offload to the remaining -Zoffload=Device ui tests --- tests/ui/offload/non_tuple_args.rs | 1 + tests/ui/offload/region_by_ref.rs | 2 ++ tests/ui/offload/type_mismatch.rs | 1 + 3 files changed, 4 insertions(+) diff --git a/tests/ui/offload/non_tuple_args.rs b/tests/ui/offload/non_tuple_args.rs index 44da33a808cb7..578aa956ecb53 100644 --- a/tests/ui/offload/non_tuple_args.rs +++ b/tests/ui/offload/non_tuple_args.rs @@ -1,4 +1,5 @@ //@ compile-flags: -Zunstable-options -Zoffload=Device -Clto=fat +//@ needs-offload #![feature(gpu_offload)] diff --git a/tests/ui/offload/region_by_ref.rs b/tests/ui/offload/region_by_ref.rs index 37ac1aa9c1b0a..2a4f7cc0b0563 100644 --- a/tests/ui/offload/region_by_ref.rs +++ b/tests/ui/offload/region_by_ref.rs @@ -1,6 +1,7 @@ //@ compile-flags: -Zunstable-options -Zoffload=Device -Clto=fat //@ edition: 2024 //@ aux-crate: offload_strategies=offload_strategies.rs +//@ needs-offload // This test ensures an error is emitted when a `Region` is nested inside another // type instead of being passed by value. @@ -9,6 +10,7 @@ #![feature(gpu_offload)] use core::offload::Region; + use offload_strategies::Dummy; fn kernel_shared(_region: &Region<'_, f32, Dummy>) {} diff --git a/tests/ui/offload/type_mismatch.rs b/tests/ui/offload/type_mismatch.rs index a75f8358b7359..47c89dac12b19 100644 --- a/tests/ui/offload/type_mismatch.rs +++ b/tests/ui/offload/type_mismatch.rs @@ -1,4 +1,5 @@ //@ compile-flags: -Zunstable-options -Zoffload=Device -Clto=fat +//@ needs-offload #![feature(core_intrinsics)]