jhuber6 created this revision. jhuber6 added reviewers: jdoerfert, JonChesterfield, saiislam, yaxunl, tra. Herald added subscribers: ormris, kerbowa, mgorny, jvesely. Herald added a project: All. jhuber6 requested review of this revision. Herald added subscribers: cfe-commits, sstefan1, MaskRay. Herald added a project: clang.
In order to do offloading compilation we need to embed files into the host and create fatbainaries. Clang uses a special binary format to bundle several files along with their metadata into a single binary image. This is currently performed using the `-fembed-offload-binary` option. However this is not very extensibile since it requires changing the command flag every time we want to add something and makes optional arguments difficult. This patch introduces a new tool called `clang-offload-binary` that behaves similarly to CUDA's `fatbinary`. This tool takes several input files with metadata and embeds it into a single image that can then be embedded in the host. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D125165 Files: clang/docs/ClangOffloadBinary.rst clang/include/clang/Basic/CodeGenOptions.h clang/include/clang/Driver/Action.h clang/include/clang/Driver/ToolChain.h clang/lib/CodeGen/BackendUtil.cpp clang/lib/Driver/Action.cpp clang/lib/Driver/Driver.cpp clang/lib/Driver/ToolChain.cpp clang/lib/Driver/ToolChains/Clang.cpp clang/lib/Driver/ToolChains/Clang.h clang/test/Driver/amdgpu-openmp-toolchain-new.c clang/test/Driver/cuda-openmp-driver.cu clang/test/Driver/cuda-phases.cu clang/test/Driver/linker-wrapper-image.c clang/test/Driver/linker-wrapper.c clang/test/Driver/openmp-offload-gpu-new.c clang/test/Driver/openmp-offload-infer.c clang/test/Frontend/embed-object.c clang/test/Frontend/embed-object.ll clang/test/lit.cfg.py clang/tools/CMakeLists.txt clang/tools/clang-offload-binary/CMakeLists.txt clang/tools/clang-offload-binary/ClangOffloadBinary.cpp
Index: clang/tools/clang-offload-binary/ClangOffloadBinary.cpp =================================================================== --- /dev/null +++ clang/tools/clang-offload-binary/ClangOffloadBinary.cpp @@ -0,0 +1,111 @@ +//===-- clang-offload-binary/ClangOffloadBinary.cpp - object file bunder --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// This tool takes several device object files and bundles them into a single +// binary image using a custom binary format. This is intended to be used to +// embed many device files into an application to create a fat binary. +// +//===---------------------------------------------------------------------===// + +#include "clang/Basic/Version.h" + +#include "llvm/Object/Binary.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/OffloadBinary.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/WithColor.h" + +using namespace llvm; +using namespace llvm::object; + +static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden); + +static cl::OptionCategory + ClangOffloadBinaryCategory("clang-offload-binary options"); + +static cl::opt<std::string> OutputFile("o", cl::Required, + cl::desc("Write output to <file>."), + cl::value_desc("file"), + cl::cat(ClangOffloadBinaryCategory)); + +static cl::list<std::string> DeviceImages( + "image", cl::ZeroOrMore, cl::desc("List of key and value arguments."), + cl::value_desc("<key>=<value>,..."), cl::cat(ClangOffloadBinaryCategory)); + +static void PrintVersion(raw_ostream &OS) { + OS << clang::getClangToolFullVersion("clang-offload-binary") << '\n'; +} + +int main(int argc, const char **argv) { + sys::PrintStackTraceOnErrorSignal(argv[0]); + cl::HideUnrelatedOptions(ClangOffloadBinaryCategory); + cl::SetVersionPrinter(PrintVersion); + cl::ParseCommandLineOptions( + argc, argv, + "A utility for bundling several object files into a single binary.\n" + "The output binary can then be embedded into the host section table\n" + "to create a fatbinary containing offloading code.\n"); + + if (Help) { + cl::PrintHelpMessage(); + return EXIT_SUCCESS; + } + + auto reportError = [argv](Error E) { + logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0])); + return EXIT_FAILURE; + }; + + SmallVector<char, 1024> BinaryData; + raw_svector_ostream OS(BinaryData); + for (StringRef Image : DeviceImages) { + StringMap<StringRef> Args; + for (StringRef Arg : llvm::split(Image, ",")) + Args.insert(Arg.split("=")); + + if (!Args.count("triple") || !Args.count("file")) + return reportError(createStringError( + inconvertibleErrorCode(), + "'file' and 'triple' are required image arguments")); + + OffloadBinary::OffloadingImage ImageBinary{}; + std::unique_ptr<llvm::MemoryBuffer> DeviceImage; + for (const auto &KeyAndValue : Args) { + StringRef Key = KeyAndValue.getKey(); + if (Key == "file") { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ObjectOrErr = + llvm::MemoryBuffer::getFileOrSTDIN(KeyAndValue.getValue()); + if (std::error_code EC = ObjectOrErr.getError()) + return reportError(errorCodeToError(EC)); + DeviceImage = std::move(*ObjectOrErr); + ImageBinary.Image = *DeviceImage; + ImageBinary.TheImageKind = getImageKind( + sys::path::extension(KeyAndValue.getValue()).drop_front()); + } else if (Key == "kind") { + ImageBinary.TheOffloadKind = getOffloadKind(KeyAndValue.getValue()); + } else { + ImageBinary.StringData[Key] = KeyAndValue.getValue(); + } + } + std::unique_ptr<MemoryBuffer> Buffer = OffloadBinary::write(ImageBinary); + OS << Buffer->getBuffer(); + } + + Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr = + FileOutputBuffer::create(OutputFile, BinaryData.size()); + if (!OutputOrErr) + return reportError(OutputOrErr.takeError()); + std::unique_ptr<FileOutputBuffer> Output = std::move(*OutputOrErr); + std::copy(BinaryData.begin(), BinaryData.end(), Output->getBufferStart()); + if (Error E = Output->commit()) + return reportError(std::move(E)); +} Index: clang/tools/clang-offload-binary/CMakeLists.txt =================================================================== --- /dev/null +++ clang/tools/clang-offload-binary/CMakeLists.txt @@ -0,0 +1,28 @@ +set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + Object + Support) + +if(NOT CLANG_BUILT_STANDALONE) + set(tablegen_deps intrinsics_gen) +endif() + +add_clang_executable(clang-offload-binary + ClangOffloadBinary.cpp + + DEPENDS + ${tablegen_deps} + ) + +set(CLANG_LINKER_WRAPPER_LIB_DEPS + clangBasic + ) + +add_dependencies(clang clang-offload-binary) + +target_link_libraries(clang-offload-binary + PRIVATE + ${CLANG_LINKER_WRAPPER_LIB_DEPS} + ) + +install(TARGETS clang-offload-binary RUNTIME DESTINATION bin) Index: clang/tools/CMakeLists.txt =================================================================== --- clang/tools/CMakeLists.txt +++ clang/tools/CMakeLists.txt @@ -10,6 +10,7 @@ add_clang_subdirectory(clang-import-test) add_clang_subdirectory(clang-nvlink-wrapper) add_clang_subdirectory(clang-linker-wrapper) +add_clang_subdirectory(clang-offload-binary) add_clang_subdirectory(clang-offload-bundler) add_clang_subdirectory(clang-offload-wrapper) add_clang_subdirectory(clang-scan-deps) Index: clang/test/lit.cfg.py =================================================================== --- clang/test/lit.cfg.py +++ clang/test/lit.cfg.py @@ -63,7 +63,7 @@ tool_dirs = [config.clang_tools_dir, config.llvm_tools_dir] tools = [ - 'apinotes-test', 'c-index-test', 'clang-diff', 'clang-format', 'clang-repl', + 'apinotes-test', 'c-index-test', 'clang-diff', 'clang-format', 'clang-repl', 'clang-offload-binary', 'clang-tblgen', 'clang-scan-deps', 'opt', 'llvm-ifs', 'yaml2obj', 'clang-linker-wrapper', ToolSubst('%clang_extdef_map', command=FindTool( 'clang-extdef-mapping'), unresolved='ignore'), Index: clang/test/Frontend/embed-object.ll =================================================================== --- clang/test/Frontend/embed-object.ll +++ clang/test/Frontend/embed-object.ll @@ -1,10 +1,10 @@ ; RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm \ -; RUN: -fembed-offload-object=%S/Inputs/empty.h,,, \ -; RUN: -fembed-offload-object=%S/Inputs/empty.h,,, -x ir %s -o - \ +; RUN: -fembed-offload-object=%S/Inputs/empty.h \ +; RUN: -fembed-offload-object=%S/Inputs/empty.h -x ir %s -o - \ ; RUN: | FileCheck %s -check-prefix=CHECK -; CHECK: @[[OBJECT_1:.+]] = private constant [120 x i8] c"\10\FF\10\AD{{.*}}\00", section ".llvm.offloading", align 8 -; CHECK: @[[OBJECT_2:.+]] = private constant [120 x i8] c"\10\FF\10\AD{{.*}}\00", section ".llvm.offloading", align 8 +; CHECK: @[[OBJECT_1:.+]] = private constant [0 x i8] zeroinitializer, section ".llvm.offloading", align 8 +; CHECK: @[[OBJECT_2:.+]] = private constant [0 x i8] zeroinitializer, section ".llvm.offloading", align 8 ; CHECK: @llvm.compiler.used = appending global [3 x ptr] [ptr @x, ptr @[[OBJECT_1]], ptr @[[OBJECT_2]]], section "llvm.metadata" @x = private constant i8 1 Index: clang/test/Frontend/embed-object.c =================================================================== --- clang/test/Frontend/embed-object.c +++ clang/test/Frontend/embed-object.c @@ -1,7 +1,6 @@ -// RUN: %clang_cc1 -x c -triple x86_64-unknown-linux-gnu -emit-llvm -fembed-offload-object=%S/Inputs/empty.h,,, -o - %s | FileCheck %s +// RUN: %clang_cc1 -x c -triple x86_64-unknown-linux-gnu -emit-llvm -fembed-offload-object=%S/Inputs/empty.h -o - %s | FileCheck %s -// CHECK: @[[OBJECT:.+]] = private constant [120 x i8] c"\10\FF\10\AD{{.*}}", section ".llvm.offloading", align 8 +// CHECK: @[[OBJECT:.+]] = private constant [0 x i8] zeroinitializer, section ".llvm.offloading", align 8 // CHECK: @llvm.compiler.used = appending global [1 x ptr] [ptr @[[OBJECT]]], section "llvm.metadata" - void foo(void) {} Index: clang/test/Driver/openmp-offload-infer.c =================================================================== --- clang/test/Driver/openmp-offload-infer.c +++ clang/test/Driver/openmp-offload-infer.c @@ -23,7 +23,8 @@ // CHECK-NVIDIA-AMDGPU: "amdgcn-amd-amdhsa" - "clang", inputs: ["[[INPUT]]", "[[HOST_BC]]"], output: "[[AMD_BC:.+]]" // CHECK-NVIDIA-AMDGPU: "nvptx64-nvidia-cuda" - "clang", inputs: ["[[INPUT]]", "[[HOST_BC]]"], output: "[[NVIDIA_PTX:.+]]" // CHECK-NVIDIA-AMDGPU: "nvptx64-nvidia-cuda" - "NVPTX::Assembler", inputs: ["[[NVIDIA_PTX]]"], output: "[[NVIDIA_CUBIN:.+]]" -// CHECK-NVIDIA-AMDGPU: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[HOST_BC]]", "[[AMD_BC]]", "[[NVIDIA_CUBIN]]"], output: "[[HOST_OBJ:.+]]" +// CHECK-NVIDIA-AMDGPU: "x86_64-unknown-linux-gnu" - "Offload::Binary", inputs: ["[[AMD_BC]]", "[[NVIDIA_CUBIN]]"], output: "[[BINARY:.+]]" +// CHECK-NVIDIA-AMDGPU: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[HOST_BC]]", "[[BINARY]]"], output: "[[HOST_OBJ:.+]]" // CHECK-NVIDIA-AMDGPU: "x86_64-unknown-linux-gnu" - "Offload::Linker", inputs: ["[[HOST_OBJ]]"], output: "a.out" // RUN: %clang -### --target=x86_64-unknown-linux-gnu -ccc-print-bindings -fopenmp \ @@ -34,7 +35,8 @@ // CHECK-ARCH-BINDINGS: "nvptx64-nvidia-cuda" - "NVPTX::Assembler", inputs: ["[[DEVICE_BC_SM_52]]"], output: "[[DEVICE_OBJ_SM_52:.*]]" // CHECK-ARCH-BINDINGS: "nvptx64-nvidia-cuda" - "clang", inputs: ["[[INPUT]]", "[[HOST_BC]]"], output: "[[DEVICE_BC_SM_70:.*]]" // CHECK-ARCH-BINDINGS: "nvptx64-nvidia-cuda" - "NVPTX::Assembler", inputs: ["[[DEVICE_BC_SM_70]]"], output: "[[DEVICE_OBJ_SM_70:.*]]" -// CHECK-ARCH-BINDINGS: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[HOST_BC]]", "[[DEVICE_OBJ_SM_52]]", "[[DEVICE_OBJ_SM_70]]"], output: "[[HOST_OBJ:.*]]" +// CHECK-ARCH-BINDINGS: "x86_64-unknown-linux-gnu" - "Offload::Binary", inputs: ["[[DEVICE_OBJ_SM_52]]", "[[DEVICE_OBJ_SM_70]]"], output: "[[BINARY:.+]]" +// CHECK-ARCH-BINDINGS: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[HOST_BC]]", "[[BINARY]]"], output: "[[HOST_OBJ:.*]]" // CHECK-ARCH-BINDINGS: "x86_64-unknown-linux-gnu" - "Offload::Linker", inputs: ["[[HOST_OBJ]]"], output: "a.out" // RUN: %clang -### --target=x86_64-unknown-linux-gnu -ccc-print-bindings -fopenmp \ Index: clang/test/Driver/openmp-offload-gpu-new.c =================================================================== --- clang/test/Driver/openmp-offload-gpu-new.c +++ clang/test/Driver/openmp-offload-gpu-new.c @@ -23,7 +23,7 @@ // RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fopenmp -fopenmp-targets=nvptx64-nvidia-cuda -Xopenmp-target=nvptx64-nvidia-cuda -march=sm_52 %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-PHASES %s -// CHECK-PHASES: 0: input, "[[INPUT:.*]]", c, (host-openmp) +// CHECK-PHASES: 0: input, "[[INPUT:.+]]", c, (host-openmp) // CHECK-PHASES: 1: preprocessor, {0}, cpp-output, (host-openmp) // CHECK-PHASES: 2: compiler, {1}, ir, (host-openmp) // CHECK-PHASES: 3: input, "[[INPUT]]", c, (device-openmp) @@ -32,16 +32,19 @@ // CHECK-PHASES: 6: offload, "host-openmp (x86_64-unknown-linux-gnu)" {2}, "device-openmp (nvptx64-nvidia-cuda)" {5}, ir // CHECK-PHASES: 7: backend, {6}, assembler, (device-openmp) // CHECK-PHASES: 8: assembler, {7}, object, (device-openmp) -// CHECK-PHASES: 9: offload, "host-openmp (x86_64-unknown-linux-gnu)" {2}, "device-openmp (nvptx64-nvidia-cuda)" {8}, ir -// CHECK-PHASES: 10: backend, {9}, assembler, (host-openmp) -// CHECK-PHASES: 11: assembler, {10}, object, (host-openmp) -// CHECK-PHASES: 12: clang-linker-wrapper, {11}, image, (host-openmp) +// CHECK-PHASES: 9: offload, "device-openmp (nvptx64-nvidia-cuda)" {8}, object +// CHECK-PHASES: 10: clang-offload-binary, {9}, image +// CHECK-PHASES: 11: offload, "host-openmp (x86_64-unknown-linux-gnu)" {2}, " (x86_64-unknown-linux-gnu)" {10}, ir +// CHECK-PHASES: 12: backend, {11}, assembler, (host-openmp) +// CHECK-PHASES: 13: assembler, {12}, object, (host-openmp) +// CHECK-PHASES: 14: clang-linker-wrapper, {13}, image, (host-openmp) // RUN: %clang -### --target=x86_64-unknown-linux-gnu -ccc-print-bindings -fopenmp -fopenmp-targets=nvptx64-nvidia-cuda -Xopenmp-target=nvptx64-nvidia-cuda -march=sm_52 -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-BINDINGS // CHECK-BINDINGS: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[INPUT:.*]]"], output: "[[HOST_BC:.*]]" // CHECK-BINDINGS: "nvptx64-nvidia-cuda" - "clang", inputs: ["[[INPUT]]", "[[HOST_BC]]"], output: "[[DEVICE_BC:.*]]" // CHECK-BINDINGS: "nvptx64-nvidia-cuda" - "NVPTX::Assembler", inputs: ["[[DEVICE_BC]]"], output: "[[DEVICE_OBJ:.*]]" -// CHECK-BINDINGS: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[HOST_BC]]", "[[DEVICE_OBJ]]"], output: "[[HOST_OBJ:.*]]" +// CHECK-BINDINGS: "x86_64-unknown-linux-gnu" - "Offload::Binary", inputs: ["[[DEVICE_OBJ]]"], output: "[[BINARY:.*]]" +// CHECK-BINDINGS: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[HOST_BC]]", "[[BINARY]]"], output: "[[HOST_OBJ:.*]]" // CHECK-BINDINGS: "x86_64-unknown-linux-gnu" - "Offload::Linker", inputs: ["[[HOST_OBJ]]"], output: "a.out" // RUN: %clang -### --target=x86_64-unknown-linux-gnu -ccc-print-bindings -fopenmp -fopenmp-targets=nvptx64-nvidia-cuda --offload-arch=sm_52 --offload-arch=sm_70 -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-ARCH-BINDINGS @@ -50,7 +53,8 @@ // CHECK-ARCH-BINDINGS: "nvptx64-nvidia-cuda" - "NVPTX::Assembler", inputs: ["[[DEVICE_BC_SM_52]]"], output: "[[DEVICE_OBJ_SM_52:.*]]" // CHECK-ARCH-BINDINGS: "nvptx64-nvidia-cuda" - "clang", inputs: ["[[INPUT]]", "[[HOST_BC]]"], output: "[[DEVICE_BC_SM_70:.*]]" // CHECK-ARCH-BINDINGS: "nvptx64-nvidia-cuda" - "NVPTX::Assembler", inputs: ["[[DEVICE_BC_SM_70]]"], output: "[[DEVICE_OBJ_SM_70:.*]]" -// CHECK-ARCH-BINDINGS: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[HOST_BC]]", "[[DEVICE_OBJ_SM_52]]", "[[DEVICE_OBJ_SM_70]]"], output: "[[HOST_OBJ:.*]]" +// CHECK-ARCH-BINDINGS: "x86_64-unknown-linux-gnu" - "Offload::Binary", inputs: ["[[DEVICE_OBJ_SM_52]]", "[[DEVICE_OBJ_SM_70]]"], output: "[[BINARY:.*]]" +// CHECK-ARCH-BINDINGS: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[HOST_BC]]", "[[BINARY]]"], output: "[[HOST_OBJ:.*]]" // CHECK-ARCH-BINDINGS: "x86_64-unknown-linux-gnu" - "Offload::Linker", inputs: ["[[HOST_OBJ]]"], output: "a.out" // RUN: %clang -### --target=x86_64-unknown-linux-gnu -ccc-print-bindings -fopenmp \ @@ -62,7 +66,8 @@ // CHECK-NVIDIA-AMDGPU: "nvptx64-nvidia-cuda" - "clang", inputs: ["[[INPUT]]", "[[HOST_BC]]"], output: "[[NVIDIA_PTX:.+]]" // CHECK-NVIDIA-AMDGPU: "nvptx64-nvidia-cuda" - "NVPTX::Assembler", inputs: ["[[NVIDIA_PTX]]"], output: "[[NVIDIA_CUBIN:.+]]" // CHECK-NVIDIA-AMDGPU: "amdgcn-amd-amdhsa" - "clang", inputs: ["[[INPUT]]", "[[HOST_BC]]"], output: "[[AMD_BC:.+]]" -// CHECK-NVIDIA-AMDGPU: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[HOST_BC]]", "[[NVIDIA_CUBIN]]", "[[AMD_BC]]"], output: "[[HOST_OBJ:.+]]" +// CHECK-NVIDIA-AMDGPU: "x86_64-unknown-linux-gnu" - "Offload::Binary", inputs: ["[[NVIDIA_CUBIN]]", "[[AMD_BC]]"], output: "[[BINARY:.*]]" +// CHECK-NVIDIA-AMDGPU: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[HOST_BC]]", "[[BINARY]]"], output: "[[HOST_OBJ:.+]]" // CHECK-NVIDIA-AMDGPU: "x86_64-unknown-linux-gnu" - "Offload::Linker", inputs: ["[[HOST_OBJ]]"], output: "a.out" // RUN: %clang -### --target=x86_64-unknown-linux-gnu -emit-llvm -S -fopenmp -fopenmp-targets=nvptx64-nvidia-cuda -Xopenmp-target=nvptx64-nvidia-cuda -march=sm_52 -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-EMIT-LLVM-IR @@ -73,7 +78,7 @@ // RUN: -nogpulib %s -o openmp-offload-gpu 2>&1 \ // RUN: | FileCheck -check-prefix=DRIVER_EMBEDDING %s -// DRIVER_EMBEDDING: -fembed-offload-object=[[CUBIN:.*\.cubin]],openmp,nvptx64-nvidia-cuda,sm_70 +// DRIVER_EMBEDDING: -fembed-offload-object={{.*}}.out // RUN: %clang -### --target=x86_64-unknown-linux-gnu -ccc-print-bindings -fopenmp -fopenmp-targets=nvptx64-nvidia-cuda \ // RUN: --offload-host-only -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-HOST-ONLY Index: clang/test/Driver/linker-wrapper.c =================================================================== --- clang/test/Driver/linker-wrapper.c +++ clang/test/Driver/linker-wrapper.c @@ -2,25 +2,28 @@ // REQUIRES: nvptx-registered-target // REQUIRES: amdgpu-registered-target -// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o \ -// RUN: -fembed-offload-object=%S/Inputs/dummy-elf.o,openmp,nvptx64-nvida-cuda,sm_70 \ -// RUN: -fembed-offload-object=%S/Inputs/dummy-elf.o,openmp,nvptx64-nvida-cuda,sm_70 +// RUN: clang-offload-binary -o %t.out \ +// RUN: --image=file=%S/Inputs/dummy-elf.o,kind=openmp,triple=nvptx64-nvidia-cuda,arch=sm_70 \ +// RUN: --image=file=%S/Inputs/dummy-elf.o,kind=openmp,triple=nvptx64-nvidia-cuda,arch=sm_70 +// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t.out // RUN: clang-linker-wrapper --host-triple x86_64-unknown-linux-gnu --dry-run -linker-path \ // RUN: /usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=NVPTX_LINK // NVPTX_LINK: nvlink{{.*}}-m64 -o {{.*}}.out -arch sm_70 {{.*}}.o {{.*}}.o -// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o \ -// RUN: -fembed-offload-object=%S/Inputs/dummy-elf.o,openmp,amdgcn-amd-amdhsa,gfx908 \ -// RUN: -fembed-offload-object=%S/Inputs/dummy-elf.o,openmp,amdgcn-amd-amdhsa,gfx908 +// RUN: clang-offload-binary -o %t.out \ +// RUN: --image=file=%S/Inputs/dummy-elf.o,kind=openmp,triple=amdgcn-amd-amdhsa,arch=gfx908 \ +// RUN: --image=file=%S/Inputs/dummy-elf.o,kind=openmp,triple=amdgcn-amd-amdhsa,arch=gfx908 +// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t.out // RUN: clang-linker-wrapper --host-triple x86_64-unknown-linux-gnu --dry-run -linker-path \ // RUN: /usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=AMDGPU_LINK // AMDGPU_LINK: lld{{.*}}-flavor gnu --no-undefined -shared -o {{.*}}.out {{.*}}.o {{.*}}.o -// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o \ -// RUN: -fembed-offload-object=%S/Inputs/dummy-elf.o,openmp,x86_64-unknown-linux-gnu, \ -// RUN: -fembed-offload-object=%S/Inputs/dummy-elf.o,openmp,x86_64-unknown-linux-gnu, +// RUN: clang-offload-binary -o %t.out \ +// RUN: --image=file=%S/Inputs/dummy-elf.o,kind=openmp,triple=x86_64-unknown-linux-gnu \ +// RUN: --image=file=%S/Inputs/dummy-elf.o,kind=openmp,triple=x86_64-unknown-linux-gnu +// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t.out // RUN: clang-linker-wrapper --host-triple x86_64-unknown-linux-gnu --dry-run -linker-path \ // RUN: /usr/bin/ld.lld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=CPU_LINK @@ -32,29 +35,33 @@ // HOST_LINK: ld.lld{{.*}}-a -b -c {{.*}}.o -o a.out -// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o \ -// RUN: -fembed-offload-object=%S/Inputs/dummy-bc.bc,openmp,nvptx64-nvida-cuda,sm_70 \ -// RUN: -fembed-offload-object=%S/Inputs/dummy-bc.bc,openmp,nvptx64-nvida-cuda,sm_70 +// RUN: clang-offload-binary -o %t.out \ +// RUN: --image=file=%S/Inputs/dummy-bc.bc,kind=openmp,triple=nvptx64-nvidia-cuda,arch=sm_70 \ +// RUN: --image=file=%S/Inputs/dummy-bc.bc,kind=openmp,triple=nvptx64-nvidia-cuda,arch=sm_70 +// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t.out // RUN: clang-linker-wrapper --host-triple x86_64-unknown-linux-gnu --dry-run -linker-path \ // RUN: /usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=LTO // LTO: ptxas{{.*}}-m64 -o {{.*}}.cubin -O2 --gpu-name sm_70 {{.*}}.s // LTO-NOT: nvlink -// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o \ -// RUN: -fembed-offload-object=%S/Inputs/dummy-elf.o,openmp,nvptx64-nvida-cuda,sm_70 \ -// RUN: -fembed-offload-object=%S/Inputs/dummy-elf.o,cuda,nvptx64-nvida-cuda,sm_70 +// RUN: clang-offload-binary -o %t.out \ +// RUN: --image=file=%S/Inputs/dummy-elf.o,kind=openmp,triple=nvptx64-nvidia-cuda,arch=sm_70 \ +// RUN: --image=file=%S/Inputs/dummy-elf.o,kind=cuda,triple=nvptx64-nvidia-cuda,arch=sm_70 +// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t.out // RUN: clang-linker-wrapper --host-triple x86_64-unknown-linux-gnu --dry-run -linker-path \ // RUN: /usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=CUDA_OMP_LINK // CUDA_OMP_LINK: nvlink{{.*}}-m64 -o {{.*}}.out -arch sm_70 {{.*}}.o {{.*}}.o -// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t-lib.o \ -// RUN: -fembed-offload-object=%S/Inputs/dummy-elf.o,openmp,nvptx64-nvida-cuda,sm_70 \ -// RUN: -fembed-offload-object=%S/Inputs/dummy-elf.o,openmp,nvptx64-nvida-cuda,sm_52 +// RUN: clang-offload-binary -o %t-lib.out \ +// RUN: --image=file=%S/Inputs/dummy-elf.o,kind=openmp,triple=nvptx64-nvidia-cuda,arch=sm_70 \ +// RUN: --image=file=%S/Inputs/dummy-elf.o,kind=cuda,triple=nvptx64-nvidia-cuda,arch=sm_52 +// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t-lib.out // RUN: llvm-ar rcs %t.a %t-lib.o -// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t-obj.o \ -// RUN: -fembed-offload-object=%S/Inputs/dummy-elf.o,openmp,nvptx64-nvida-cuda,sm_70 +// RUN: clang-offload-binary -o %t.out \ +// RUN: --image=file=%S/Inputs/dummy-elf.o,kind=openmp,triple=nvptx64-nvidia-cuda,arch=sm_70 +// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t-obj.o -fembed-offload-object=%t.out // RUN: clang-linker-wrapper --host-triple x86_64-unknown-linux-gnu --dry-run -linker-path \ // RUN: /usr/bin/ld -- %t.a %t-obj.o -o a.out 2>&1 | FileCheck %s --check-prefix=STATIC-LIBRARY Index: clang/test/Driver/linker-wrapper-image.c =================================================================== --- clang/test/Driver/linker-wrapper-image.c +++ clang/test/Driver/linker-wrapper-image.c @@ -2,8 +2,9 @@ // REQUIRES: nvptx-registered-target // REQUIRES: amdgpu-registered-target +// RUN: clang-offload-binary -o %t.out --image=file=%S/Inputs/dummy-elf.o,kind=openmp,triple=nvptx64-nvidia-cuda,arch=sm_70 // RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o \ -// RUN: -fembed-offload-object=%S/Inputs/dummy-elf.o,openmp,nvptx64-nvida-cuda,sm_70 +// RUN: -fembed-offload-object=%t.out // RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple x86_64-unknown-linux-gnu \ // RUN: -linker-path /usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=OPENMP Index: clang/test/Driver/cuda-phases.cu =================================================================== --- clang/test/Driver/cuda-phases.cu +++ clang/test/Driver/cuda-phases.cu @@ -223,9 +223,9 @@ // // RUN: %clang -### -target powerpc64le-ibm-linux-gnu -ccc-print-phases --offload-new-driver \ // RUN: --offload-arch=sm_52 --offload-arch=sm_70 %s 2>&1 | FileCheck --check-prefix=NEW_DRIVER %s -// NEW_DRIVER: 0: input, "[[INPUT:.*]]", cuda, (host-cuda) -// NEW_DRIVER: 1: preprocessor, {0}, cuda-cpp-output, (host-cuda) -// NEW_DRIVER: 2: compiler, {1}, ir, (host-cuda) +// NEW_DRIVER: 0: input, "[[INPUT:.+]]", cuda +// NEW_DRIVER: 1: preprocessor, {0}, cuda-cpp-output +// NEW_DRIVER: 2: compiler, {1}, ir // NEW_DRIVER: 3: input, "[[INPUT]]", cuda, (device-cuda, sm_52) // NEW_DRIVER: 4: preprocessor, {3}, cuda-cpp-output, (device-cuda, sm_52) // NEW_DRIVER: 5: compiler, {4}, ir, (device-cuda, sm_52) @@ -234,15 +234,18 @@ // NEW_DRIVER: 8: offload, "device-cuda (nvptx64-nvidia-cuda:sm_52)" {7}, object // NEW_DRIVER: 9: offload, "device-cuda (nvptx64-nvidia-cuda:sm_52)" {6}, assembler // NEW_DRIVER: 10: linker, {8, 9}, cuda-fatbin, (device-cuda, sm_52) -// NEW_DRIVER: 11: input, "[[INPUT]]", cuda, (device-cuda, sm_70) -// NEW_DRIVER: 12: preprocessor, {11}, cuda-cpp-output, (device-cuda, sm_70) -// NEW_DRIVER: 13: compiler, {12}, ir, (device-cuda, sm_70) -// NEW_DRIVER: 14: backend, {13}, assembler, (device-cuda, sm_70) -// NEW_DRIVER: 15: assembler, {14}, object, (device-cuda, sm_70) -// NEW_DRIVER: 16: offload, "device-cuda (nvptx64-nvidia-cuda:sm_70)" {15}, object -// NEW_DRIVER: 17: offload, "device-cuda (nvptx64-nvidia-cuda:sm_70)" {14}, assembler -// NEW_DRIVER: 18: linker, {16, 17}, cuda-fatbin, (device-cuda, sm_70) -// NEW_DRIVER: 19: offload, "host-cuda (powerpc64le-ibm-linux-gnu)" {2}, "device-cuda (nvptx64-nvidia-cuda:sm_52)" {10}, "device-cuda (nvptx64-nvidia-cuda:sm_70)" {18}, ir -// NEW_DRIVER: 20: backend, {19}, assembler, (host-cuda) -// NEW_DRIVER: 21: assembler, {20}, object, (host-cuda) -// NEW_DRIVER: 22: clang-linker-wrapper, {21}, image, (host-cuda) +// NEW_DRIVER: 11: offload, "device-cuda (nvptx64-nvidia-cuda:sm_52)" {10}, cuda-fatbin +// NEW_DRIVER: 12: input, "[[INPUT]]", cuda, (device-cuda, sm_70) +// NEW_DRIVER: 13: preprocessor, {12}, cuda-cpp-output, (device-cuda, sm_70) +// NEW_DRIVER: 14: compiler, {13}, ir, (device-cuda, sm_70) +// NEW_DRIVER: 15: backend, {14}, assembler, (device-cuda, sm_70) +// NEW_DRIVER: 16: assembler, {15}, object, (device-cuda, sm_70) +// NEW_DRIVER: 17: offload, "device-cuda (nvptx64-nvidia-cuda:sm_70)" {16}, object +// NEW_DRIVER: 18: offload, "device-cuda (nvptx64-nvidia-cuda:sm_70)" {15}, assembler +// NEW_DRIVER: 19: linker, {17, 18}, cuda-fatbin, (device-cuda, sm_70) +// NEW_DRIVER: 20: offload, "device-cuda (nvptx64-nvidia-cuda:sm_70)" {19}, cuda-fatbin +// NEW_DRIVER: 21: clang-offload-binary, {11, 20}, image +// NEW_DRIVER: 22: offload, " (powerpc64le-ibm-linux-gnu)" {2}, " (powerpc64le-ibm-linux-gnu)" {21}, ir +// NEW_DRIVER: 23: backend, {22}, assembler, (host-cuda) +// NEW_DRIVER: 24: assembler, {23}, object, (host-cuda) +// NEW_DRIVER: 25: clang-linker-wrapper, {24}, image, (host-cuda) Index: clang/test/Driver/cuda-openmp-driver.cu =================================================================== --- clang/test/Driver/cuda-openmp-driver.cu +++ clang/test/Driver/cuda-openmp-driver.cu @@ -11,7 +11,8 @@ // BINDINGS-NEXT: "nvptx64-nvidia-cuda" - "clang", inputs: ["[[INPUT]]"], output: "[[PTX_SM_70:.+]]" // BINDINGS-NEXT: "nvptx64-nvidia-cuda" - "NVPTX::Assembler", inputs: ["[[PTX_SM_70:.+]]"], output: "[[CUBIN_SM_70:.+]]" // BINDINGS-NEXT: "nvptx64-nvidia-cuda" - "NVPTX::Linker", inputs: ["[[CUBIN_SM_70]]", "[[PTX_SM_70:.+]]"], output: "[[FATBIN_SM_70:.+]]" -// BINDINGS-NEXT: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[INPUT]]", "[[FATBIN_SM_35]]", "[[FATBIN_SM_70]]"], output: "[[HOST_OBJ:.+]]" +// BINDINGS-NEXT: "x86_64-unknown-linux-gnu" - "Offload::Binary", inputs: ["[[FATBIN_SM_35]]", "[[FATBIN_SM_70]]"], output: "[[BINARY:.+]]" +// BINDINGS-NEXT: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[INPUT]]", "[[BINARY]]"], output: "[[HOST_OBJ:.+]]" // BINDINGS-NEXT: "x86_64-unknown-linux-gnu" - "Offload::Linker", inputs: ["[[HOST_OBJ]]"], output: "a.out" // RUN: %clang -### -nocudalib --offload-new-driver %s 2>&1 | FileCheck -check-prefix RDC %s Index: clang/test/Driver/amdgpu-openmp-toolchain-new.c =================================================================== --- clang/test/Driver/amdgpu-openmp-toolchain-new.c +++ clang/test/Driver/amdgpu-openmp-toolchain-new.c @@ -15,7 +15,7 @@ // RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa -Xopenmp-target=amdgcn-amd-amdhsa -march=gfx906 %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-PHASES %s -// CHECK-PHASES: 0: input, "[[INPUT:.*]]", c, (host-openmp) +// CHECK-PHASES: 0: input, "[[INPUT:.+]]", c, (host-openmp) // CHECK-PHASES: 1: preprocessor, {0}, cpp-output, (host-openmp) // CHECK-PHASES: 2: compiler, {1}, ir, (host-openmp) // CHECK-PHASES: 3: input, "[[INPUT]]", c, (device-openmp) @@ -24,10 +24,12 @@ // CHECK-PHASES: 6: offload, "host-openmp (x86_64-unknown-linux-gnu)" {2}, "device-openmp (amdgcn-amd-amdhsa)" {5}, ir // CHECK-PHASES: 7: backend, {6}, assembler, (device-openmp) // CHECK-PHASES: 8: assembler, {7}, object, (device-openmp) -// CHECK-PHASES: 9: offload, "host-openmp (x86_64-unknown-linux-gnu)" {2}, "device-openmp (amdgcn-amd-amdhsa)" {8}, ir -// CHECK-PHASES: 10: backend, {9}, assembler, (host-openmp) -// CHECK-PHASES: 11: assembler, {10}, object, (host-openmp) -// CHECK-PHASES: 12: clang-linker-wrapper, {11}, image, (host-openmp) +// CHECK-PHASES: 9: offload, "device-openmp (amdgcn-amd-amdhsa)" {8}, object +// CHECK-PHASES: 10: clang-offload-binary, {9}, image +// CHECK-PHASES: 11: offload, "host-openmp (x86_64-unknown-linux-gnu)" {2}, " (x86_64-unknown-linux-gnu)" {10}, ir +// CHECK-PHASES: 12: backend, {11}, assembler, (host-openmp) +// CHECK-PHASES: 13: assembler, {12}, object, (host-openmp) +// CHECK-PHASES: 14: clang-linker-wrapper, {13}, image, (host-openmp) // handling of --libomptarget-amdgpu-bc-path // RUN: %clang -### --target=x86_64-unknown-linux-gnu -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa -Xopenmp-target=amdgcn-amd-amdhsa -march=gfx803 --libomptarget-amdgpu-bc-path=%S/Inputs/hip_dev_lib/libomptarget-amdgpu-gfx803.bc %s 2>&1 | FileCheck %s --check-prefix=CHECK-LIBOMPTARGET @@ -38,9 +40,10 @@ // RUN: %clang -### --target=x86_64-unknown-linux-gnu -ccc-print-bindings -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa -Xopenmp-target=amdgcn-amd-amdhsa -march=gfx803 -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-BINDINGS // RUN: %clang -### --target=x86_64-unknown-linux-gnu -ccc-print-bindings -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa --offload-arch=gfx803 -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-BINDINGS -// CHECK-BINDINGS: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[INPUT:.*]]"], output: "[[HOST_BC:.*]]" -// CHECK-BINDINGS: "amdgcn-amd-amdhsa" - "clang", inputs: ["[[INPUT]]", "[[HOST_BC]]"], output: "[[DEVICE_BC:.*]]" -// CHECK-BINDINGS: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[HOST_BC]]", "[[DEVICE_BC]]"], output: "[[HOST_OBJ:.*]]" +// CHECK-BINDINGS: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[INPUT:.+]]"], output: "[[HOST_BC:.+]]" +// CHECK-BINDINGS: "amdgcn-amd-amdhsa" - "clang", inputs: ["[[INPUT]]", "[[HOST_BC]]"], output: "[[DEVICE_BC:.+]]" +// CHECK-BINDINGS: "x86_64-unknown-linux-gnu" - "Offload::Binary", inputs: ["[[DEVICE_BC]]"], output: "[[BINARY:.+]]" +// CHECK-BINDINGS: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[HOST_BC]]", "[[BINARY]]"], output: "[[HOST_OBJ:.+]]" // CHECK-BINDINGS: "x86_64-unknown-linux-gnu" - "Offload::Linker", inputs: ["[[HOST_OBJ]]"], output: "a.out" // RUN: %clang -### --target=x86_64-unknown-linux-gnu -emit-llvm -S -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa -Xopenmp-target=amdgcn-amd-amdhsa -march=gfx803 -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-EMIT-LLVM-IR Index: clang/lib/Driver/ToolChains/Clang.h =================================================================== --- clang/lib/Driver/ToolChains/Clang.h +++ clang/lib/Driver/ToolChains/Clang.h @@ -170,6 +170,19 @@ const char *LinkingOutput) const override; }; +/// Offload binary tool. +class LLVM_LIBRARY_VISIBILITY OffloadBinary final : public Tool { +public: + OffloadBinary(const ToolChain &TC) + : Tool("Offload::Binary", "clang-offload-binary", TC) {} + + bool hasIntegratedCPP() const override { return false; } + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + /// Linker wrapper tool. class LLVM_LIBRARY_VISIBILITY LinkerWrapper final : public Tool { const Tool *Linker; Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -6979,22 +6979,9 @@ // Host-side offloading recieves the device object files and embeds it in a // named section including the associated target triple and architecture. - for (const InputInfo Input : HostOffloadingInputs) { - const Action *OffloadAction = Input.getAction(); - const ToolChain *TC = OffloadAction->getOffloadingToolChain(); - const ArgList &TCArgs = - C.getArgsForToolChain(TC, OffloadAction->getOffloadingArch(), - OffloadAction->getOffloadingDeviceKind()); - StringRef File = C.getArgs().MakeArgString(TC->getInputFilename(Input)); - StringRef Arch = (OffloadAction->getOffloadingArch()) - ? OffloadAction->getOffloadingArch() - : TCArgs.getLastArgValue(options::OPT_march_EQ); - - CmdArgs.push_back(Args.MakeArgString( - "-fembed-offload-object=" + File + "," + - Action::GetOffloadKindName(OffloadAction->getOffloadingDeviceKind()) + - "," + TC->getTripleString() + "," + Arch)); - } + for (const InputInfo Input : HostOffloadingInputs) + CmdArgs.push_back(Args.MakeArgString("-fembed-offload-object=" + + TC.getInputFilename(Input))); if (Triple.isAMDGPU()) { handleAMDGPUCodeObjectVersionOptions(D, Args, CmdArgs); @@ -8231,6 +8218,42 @@ CmdArgs, Inputs, Output)); } +void OffloadBinary::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + // Add the output file name. + assert(Output.isFilename() && "Invalid output."); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + // Create the inputs to bundle the needed metadata. + for (const InputInfo &Input : Inputs) { + const Action *OffloadAction = Input.getAction(); + const ToolChain *TC = OffloadAction->getOffloadingToolChain(); + const ArgList &TCArgs = + C.getArgsForToolChain(TC, OffloadAction->getOffloadingArch(), + OffloadAction->getOffloadingDeviceKind()); + StringRef File = C.getArgs().MakeArgString(TC->getInputFilename(Input)); + StringRef Arch = (OffloadAction->getOffloadingArch()) + ? OffloadAction->getOffloadingArch() + : TCArgs.getLastArgValue(options::OPT_march_EQ); + + CmdArgs.push_back(Args.MakeArgString( + "--image=file=" + File + "," + "triple=" + TC->getTripleString() + "," + + "arch=" + Arch + "," + "kind=" + + Action::GetOffloadKindName(OffloadAction->getOffloadingDeviceKind()))); + } + + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::None(), + Args.MakeArgString(getToolChain().GetProgramPath(getShortName())), + CmdArgs, Inputs, Output)); +} + void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, Index: clang/lib/Driver/ToolChain.cpp =================================================================== --- clang/lib/Driver/ToolChain.cpp +++ clang/lib/Driver/ToolChain.cpp @@ -328,6 +328,12 @@ return OffloadWrapper.get(); } +Tool *ToolChain::getOffloadBinary() const { + if (!OffloadBinary) + OffloadBinary.reset(new tools::OffloadBinary(*this)); + return OffloadBinary.get(); +} + Tool *ToolChain::getLinkerWrapper() const { if (!LinkerWrapper) LinkerWrapper.reset(new tools::LinkerWrapper(*this, getLink())); @@ -373,6 +379,8 @@ case Action::OffloadWrapperJobClass: return getOffloadWrapper(); + case Action::OffloadBinaryJobClass: + return getOffloadBinary(); case Action::LinkerWrapperJobClass: return getLinkerWrapper(); } Index: clang/lib/Driver/Driver.cpp =================================================================== --- clang/lib/Driver/Driver.cpp +++ clang/lib/Driver/Driver.cpp @@ -4382,6 +4382,7 @@ getFinalPhase(Args) == phases::Preprocess)) return HostAction; + ActionList OffloadActions; OffloadAction::DeviceDependences DDeps; const Action::OffloadKind OffloadKinds[] = { @@ -4456,7 +4457,11 @@ auto TCAndArch = TCAndArchs.begin(); for (Action *A : DeviceActions) { - DDeps.add(*A, *TCAndArch->first, TCAndArch->second.data(), Kind); + if (DeviceOnly) + DDeps.add(*A, *TCAndArch->first, TCAndArch->second.data(), Kind); + OffloadAction::DeviceDependences DDep; + DDep.add(*A, *TCAndArch->first, TCAndArch->second.data(), Kind); + OffloadActions.push_back(C.MakeAction<OffloadAction>(DDep, A->getType())); ++TCAndArch; } } @@ -4464,10 +4469,15 @@ if (DeviceOnly) return C.MakeAction<OffloadAction>(DDeps, types::TY_Nothing); + Action *OffloadBinary = + C.MakeAction<OffloadBinaryJobAction>(OffloadActions, types::TY_Image); + OffloadAction::DeviceDependences DDep; + DDep.add(*OffloadBinary, *C.getSingleOffloadToolChain<Action::OFK_Host>(), + nullptr, Action::OFK_None); OffloadAction::HostDependence HDep( *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), - /*BoundArch=*/nullptr, DDeps); - return C.MakeAction<OffloadAction>(HDep, DDeps); + /*BoundArch=*/nullptr, DDep); + return C.MakeAction<OffloadAction>(HDep, DDep); } Action *Driver::ConstructPhaseAction( Index: clang/lib/Driver/Action.cpp =================================================================== --- clang/lib/Driver/Action.cpp +++ clang/lib/Driver/Action.cpp @@ -45,6 +45,8 @@ return "clang-offload-unbundler"; case OffloadWrapperJobClass: return "clang-offload-wrapper"; + case OffloadBinaryJobClass: + return "clang-offload-binary"; case LinkerWrapperJobClass: return "clang-linker-wrapper"; case StaticLibJobClass: @@ -432,6 +434,12 @@ types::ID Type) : JobAction(OffloadWrapperJobClass, Inputs, Type) {} +void OffloadBinaryJobAction::anchor() {} + +OffloadBinaryJobAction::OffloadBinaryJobAction(ActionList &Inputs, + types::ID Type) + : JobAction(OffloadBinaryJobClass, Inputs, Type) {} + void LinkerWrapperJobAction::anchor() {} LinkerWrapperJobAction::LinkerWrapperJobAction(ActionList &Inputs, Index: clang/lib/CodeGen/BackendUtil.cpp =================================================================== --- clang/lib/CodeGen/BackendUtil.cpp +++ clang/lib/CodeGen/BackendUtil.cpp @@ -1211,33 +1211,16 @@ return; for (StringRef OffloadObject : CGOpts.OffloadObjects) { - SmallVector<StringRef, 4> ObjectFields; - OffloadObject.split(ObjectFields, ','); - - if (ObjectFields.size() != 4) { - auto DiagID = Diags.getCustomDiagID( - DiagnosticsEngine::Error, "Expected at least four arguments '%0'"); - Diags.Report(DiagID) << OffloadObject; - return; - } - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ObjectOrErr = - llvm::MemoryBuffer::getFileOrSTDIN(ObjectFields[0]); + llvm::MemoryBuffer::getFileOrSTDIN(OffloadObject); if (std::error_code EC = ObjectOrErr.getError()) { auto DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "could not open '%0' for embedding"); - Diags.Report(DiagID) << ObjectFields[0]; + Diags.Report(DiagID) << OffloadObject; return; } - OffloadBinary::OffloadingImage Image{}; - Image.TheImageKind = getImageKind(ObjectFields[0].rsplit(".").second); - Image.TheOffloadKind = getOffloadKind(ObjectFields[1]); - Image.StringData = {{"triple", ObjectFields[2]}, {"arch", ObjectFields[3]}}; - Image.Image = **ObjectOrErr; - - std::unique_ptr<MemoryBuffer> OffloadBuffer = OffloadBinary::write(Image); - llvm::embedBufferInModule(*M, *OffloadBuffer, ".llvm.offloading", + llvm::embedBufferInModule(*M, **ObjectOrErr, ".llvm.offloading", Align(OffloadBinary::getAlignment())); } } Index: clang/include/clang/Driver/ToolChain.h =================================================================== --- clang/include/clang/Driver/ToolChain.h +++ clang/include/clang/Driver/ToolChain.h @@ -151,6 +151,7 @@ mutable std::unique_ptr<Tool> IfsMerge; mutable std::unique_ptr<Tool> OffloadBundler; mutable std::unique_ptr<Tool> OffloadWrapper; + mutable std::unique_ptr<Tool> OffloadBinary; mutable std::unique_ptr<Tool> LinkerWrapper; Tool *getClang() const; @@ -162,6 +163,7 @@ Tool *getClangAs() const; Tool *getOffloadBundler() const; Tool *getOffloadWrapper() const; + Tool *getOffloadBinary() const; Tool *getLinkerWrapper() const; mutable bool SanitizerArgsChecked = false; Index: clang/include/clang/Driver/Action.h =================================================================== --- clang/include/clang/Driver/Action.h +++ clang/include/clang/Driver/Action.h @@ -74,6 +74,7 @@ OffloadBundlingJobClass, OffloadUnbundlingJobClass, OffloadWrapperJobClass, + OffloadBinaryJobClass, LinkerWrapperJobClass, StaticLibJobClass, @@ -669,6 +670,17 @@ } }; +class OffloadBinaryJobAction : public JobAction { + void anchor() override; + +public: + OffloadBinaryJobAction(ActionList &Inputs, types::ID Type); + + static bool classof(const Action *A) { + return A->getKind() == OffloadBinaryJobClass; + } +}; + class LinkerWrapperJobAction : public JobAction { void anchor() override; Index: clang/include/clang/Basic/CodeGenOptions.h =================================================================== --- clang/include/clang/Basic/CodeGenOptions.h +++ clang/include/clang/Basic/CodeGenOptions.h @@ -276,12 +276,8 @@ /// CUDA runtime back-end for incorporating them into host-side object file. std::string CudaGpuBinaryFileName; - /// List of filenames and metadata passed in using the -fembed-offload-object - /// option to embed device-side offloading objects into the host as a named - /// section. Input passed in as 'filename,kind,triple,arch'. - /// - /// NOTE: This will need to be expanded whenever we want to pass in more - /// metadata, at some point this should be its own clang tool. + /// List of filenames passed in using the -fembed-offload-object option. These + /// are offloading binaries containing device images and metadata. std::vector<std::string> OffloadObjects; /// The name of the file to which the backend should save YAML optimization Index: clang/docs/ClangOffloadBinary.rst =================================================================== --- /dev/null +++ clang/docs/ClangOffloadBinary.rst @@ -0,0 +1,55 @@ +==================== +Clang Offload Binary +==================== + +.. contents:: + :local: + +.. _clang-offload-binary: + +Introduction +============ + +This tool bundles device files into a single image containing necessary +metadata. We use a custom binary format for bundling all the device images +together. The image format is a small header wrapping around a string map. This +tool creates bundled binaries so that they can be embedded into the host to +create a fat-binary. + +Usage +===== + +This tool can be used with the following arguments. Generally information is +passed as a key-value pair to the ``image=`` argument. The ``file``, ``triple``, +and ``arch`` arguments are considered mandatory to make a valid image. + +.. code-block:: console + + OVERVIEW: A utility for bundling several object files into a single binary. + The output binary can then be embedded into the host section table + to create a fatbinary containing offloading code. + + USAGE: clang-offload-binary [options] + + OPTIONS: + + Generic Options: + + --help - Display available options (--help-hidden for more) + --help-list - Display list of available options (--help-list-hidden for more) + --version - Display the version of this program + + clang-offload-binary options: + + --image=<<key>=<value>,...> - List of key and value arguments. + -o=<file> - Write output to <file>. + +Example +======= + +This tool simply takes many input files from the ``image`` option and creates a +single output file with all the images combined. + +.. code-block:: console + + clang-offload-binary -o out.bin --image=file=input.o,triple=nvptx64,arch=sm_70
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits