https://github.com/yxsamliu updated https://github.com/llvm/llvm-project/pull/212342
>From 0d62f82e60c2d7a1030796b855df0a3eafd4a13c Mon Sep 17 00:00:00 2001 From: "Yaxun (Sam) Liu" <[email protected]> Date: Mon, 27 Jul 2026 15:07:16 -0400 Subject: [PATCH] [HIP] Support device-only linking of bitcode offload binaries The new offload driver packages multi-architecture bitcode in LLVM offload binaries. A later `--hip-link --offload-device-only` invocation treated these `.bc` inputs as host LLVM IR and dropped them before linking. Pass these inputs directly to clang-linker-wrapper when producing a device fat binary. The wrapper can then extract and link each requested GPU architecture. --- clang/lib/Driver/Driver.cpp | 18 ++++++- clang/lib/Driver/ToolChains/Clang.cpp | 16 +++---- clang/test/Driver/hip-link-offload-binary.c | 53 +++++++++++++++++++++ 3 files changed, 78 insertions(+), 9 deletions(-) create mode 100644 clang/test/Driver/hip-link-offload-binary.c diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 2ef9ffe0b9426..38795f7c2ae7a 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -4542,6 +4542,14 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, bool UseNewOffloadingDriver = Args.hasFlag( options::OPT_offload_new_driver, options::OPT_no_offload_new_driver, C.getActiveOffloadKinds() != Action::OFK_None); + bool HIPRDCDeviceOnlyFatBin = + UseNewOffloadingDriver && C.isOffloadingHostKind(Action::OFK_HIP) && + offloadDeviceOnly() && Args.hasArg(options::OPT_hip_link) && + Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false) && + getFinalPhase(Args) == phases::Link && + !Args.hasArg(options::OPT_emit_llvm) && + Args.hasFlag(options::OPT_gpu_bundle_output, + options::OPT_no_gpu_bundle_output, true); // Builder to be used to build offloading actions. std::unique_ptr<OffloadingActionBuilder> OffloadBuilder = @@ -4567,6 +4575,12 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, // Build the pipeline for this file. Action *Current = C.MakeAction<InputAction>(*InputArg, InputType); + // Device-only HIP links consume packaged offload bitcode directly. + if (HIPRDCDeviceOnlyFatBin && InputType == types::TY_LLVM_BC) { + LinkerInputs.push_back(Current); + continue; + } + std::string CUID; if (CUIDOpts.isEnabled() && types::isSrcFile(InputType)) { CUID = CUIDOpts.getCUID(InputArg->getValue(), Args); @@ -4693,7 +4707,9 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, LA = C.MakeAction<StaticLibJobAction>(LinkerInputs, types::TY_Image); } else if (UseNewOffloadingDriver || Args.hasArg(options::OPT_offload_link)) { - LA = C.MakeAction<LinkerWrapperJobAction>(LinkerInputs, types::TY_Image); + LA = C.MakeAction<LinkerWrapperJobAction>( + LinkerInputs, + HIPRDCDeviceOnlyFatBin ? types::TY_HIP_FATBIN : types::TY_Image); LA->propagateHostOffloadInfo(C.getActiveOffloadKinds(), /*BA=*/{}); } else { diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 0904d116b5cba..94f9a26aac39f 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -9839,6 +9839,11 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, OPT_fno_slp_vectorize, OPT_hipstdpar}; const llvm::DenseSet<unsigned> LinkerOptions{OPT_mllvm, OPT_Zlinker_input}; + // Suppress verbose output for HIP non-RDC fat binaries because it confuses + // CMake implicit linker argument parsing. + bool SuppressHIPNoRDCVerbose = + JA.getType() == types::TY_HIP_FATBIN && + !Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false); auto ToolChainHasRT = [&](const ToolChain &TC, StringRef Name) { return TC.getVFS().exists( TC.getCompilerRT(Args, Name, ToolChain::FT_Static)); @@ -9860,8 +9865,7 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, }; auto ShouldForward = [&](const llvm::DenseSet<unsigned> &Set, Arg *A, const ToolChain &TC) { - // CMake hack to avoid printing verbose informatoin for HIP non-RDC mode. - if (A->getOption().matches(OPT_v) && JA.getType() == types::TY_HIP_FATBIN) + if (A->getOption().matches(OPT_v) && SuppressHIPNoRDCVerbose) return false; return (Set.contains(A->getOption().getID()) || (A->getOption().getGroup().isValid() && @@ -9979,11 +9983,7 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString("--host-triple=" + getToolChain().getTripleString())); - // CMake hack, suppress passing verbose arguments for the special-case HIP - // non-RDC mode compilation. This confuses default CMake implicit linker - // argument parsing when the language is set to HIP and the system linker is - // also `ld.lld`. - if (Args.hasArg(options::OPT_v) && JA.getType() != types::TY_HIP_FATBIN) + if (Args.hasArg(options::OPT_v) && !SuppressHIPNoRDCVerbose) CmdArgs.push_back("--wrapper-verbose"); if (Arg *A = Args.getLastArg(options::OPT_cuda_path_EQ)) { CmdArgs.push_back( @@ -10071,7 +10071,7 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, // We use action type to differentiate two use cases of the linker wrapper. // TY_Image for normal linker wrapper work. - // TY_HIP_FATBIN for HIP fno-gpu-rdc emitting a fat binary without wrapping. + // TY_HIP_FATBIN for HIP device-only links emitting a fat binary directly. assert(JA.getType() == types::TY_HIP_FATBIN || JA.getType() == types::TY_Image); if (JA.getType() == types::TY_HIP_FATBIN) { diff --git a/clang/test/Driver/hip-link-offload-binary.c b/clang/test/Driver/hip-link-offload-binary.c new file mode 100644 index 0000000000000..5cb3b84677f67 --- /dev/null +++ b/clang/test/Driver/hip-link-offload-binary.c @@ -0,0 +1,53 @@ +// REQUIRES: amdgpu-registered-target +// REQUIRES: lld + +// RUN: %clang --target=amdgcn-amd-amdhsa -emit-llvm -c -nogpulib -DVAR=x %s -o %t.x.bc +// RUN: %clang --target=amdgcn-amd-amdhsa -emit-llvm -c -nogpulib -DVAR=y %s -o %t.y.bc +// RUN: llvm-offload-binary -o %t.x.bundle.bc \ +// RUN: --image=file=%t.x.bc,triple=amdgcn-amd-amdhsa,arch=gfx906,kind=hip \ +// RUN: --image=file=%t.x.bc,triple=amdgcn-amd-amdhsa,arch=gfx942,kind=hip +// RUN: llvm-offload-binary -o %t.y.bundle.bc \ +// RUN: --image=file=%t.y.bc,triple=amdgcn-amd-amdhsa,arch=gfx906,kind=hip \ +// RUN: --image=file=%t.y.bc,triple=amdgcn-amd-amdhsa,arch=gfx942,kind=hip + +// RUN: %clang -### -fgpu-rdc --hip-link --cuda-device-only \ +// RUN: --offload-arch=gfx906 --offload-arch=gfx942 \ +// RUN: %t.x.bundle.bc %t.y.bundle.bc -o %t.hipfb 2>&1 \ +// RUN: | FileCheck %s --check-prefix=DRIVER +// DRIVER: "{{.*}}clang-linker-wrapper" +// DRIVER-SAME: "--should-extract=gfx906" +// DRIVER-SAME: "--should-extract=gfx942" +// DRIVER-SAME: "--emit-fatbin-only" "-o" "{{.*}}.hipfb" +// DRIVER-SAME: "{{.*}}.x.bundle.bc" "{{.*}}.y.bundle.bc" + +// RUN: %clang -### -v -fgpu-rdc --hip-link --cuda-device-only \ +// RUN: --offload-arch=gfx906 %t.x.bundle.bc -o %t.hipfb 2>&1 \ +// RUN: | FileCheck %s --check-prefix=VERBOSE +// VERBOSE: "{{.*}}clang-linker-wrapper" +// VERBOSE-SAME: "--device-compiler=amdgcn-amd-amdhsa=-v" +// VERBOSE-SAME: "--wrapper-verbose" +// VERBOSE-SAME: "--emit-fatbin-only" + +// RUN: %clang -fgpu-rdc --hip-link --cuda-device-only \ +// RUN: --offload-arch=gfx906 --offload-arch=gfx942 \ +// RUN: %t.x.bundle.bc %t.y.bundle.bc -o %t.hipfb +// RUN: clang-offload-bundler -type=o -list -input=%t.hipfb \ +// RUN: | FileCheck %s --check-prefix=ARCH +// ARCH-DAG: hip-amdgcn-amd-amdhsa--gfx906 +// ARCH-DAG: hip-amdgcn-amd-amdhsa--gfx942 + +// RUN: %clang -### -c -fgpu-rdc --hip-link --cuda-device-only \ +// RUN: --offload-arch=gfx906 %t.x.bundle.bc -o %t.o 2>&1 \ +// RUN: | FileCheck %s --check-prefix=COMPILE +// COMPILE: "-cc1" +// COMPILE-NOT: "{{.*}}clang-linker-wrapper" + +// RUN: %clang -### -emit-llvm -fgpu-rdc --hip-link --cuda-device-only \ +// RUN: --offload-arch=gfx906 %t.x.bundle.bc -o %t.linked.bc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=NO-FATBIN --allow-empty +// RUN: %clang -### --no-gpu-bundle-output -fgpu-rdc --hip-link \ +// RUN: --cuda-device-only --offload-arch=gfx906 %t.x.bundle.bc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=NO-FATBIN --allow-empty +// NO-FATBIN-NOT: "--emit-fatbin-only" + +__attribute__((visibility("protected"), used)) int VAR; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
