This patch adds an Offload Wrapper for the SYCL kind. This is an essential step for SYCL offloading and the compilation flow. The usage of offload wrapping is added to the clang-linker-wrapper tool. Modifications: Implemented `bundleSYCL()` function to handle SYCL image bundling. Implemented `wrapSYCLBinaries()` function that is invoked from clang-linker-wrapper. SYCL Offload Wrapping uses specific data structures such as `__sycl.tgt_device_image` and `__sycl.tgt_bin_desc`. Each SYCL image maintains its own symbol table (unlike shared global tables in other targets). Therefore, symbols are encoded explicitly during the offload wrapping. Also, images refer to their own Offloading Entries arrays unlike other targets. The proposed `__sycl.tgt_device_image` uses Version 3 to differentiate from images generated by Intel DPC++. The structure proposed in this patch doesn't have fields deprecated in DPC++.
140 lines
5.0 KiB
C++
140 lines
5.0 KiB
C++
//===- llvm-offload-wrapper: Create runtime registration code for devices -===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Provides a utility for generating runtime registration code for device code.
|
|
// We take a binary image (CUDA fatbinary, HIP offload bundle, LLVM binary) and
|
|
// create a new IR module that calls the respective runtime to load it on the
|
|
// device.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Bitcode/BitcodeWriter.h"
|
|
#include "llvm/Frontend/Offloading/OffloadWrapper.h"
|
|
#include "llvm/Frontend/Offloading/Utility.h"
|
|
#include "llvm/Object/OffloadBinary.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/FileOutputBuffer.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/InitLLVM.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/Support/Path.h"
|
|
#include "llvm/Support/Signals.h"
|
|
#include "llvm/Support/StringSaver.h"
|
|
#include "llvm/Support/WithColor.h"
|
|
#include "llvm/TargetParser/Host.h"
|
|
|
|
using namespace llvm;
|
|
|
|
static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
|
|
|
|
static cl::OptionCategory
|
|
OffloadWrapeprCategory("llvm-offload-wrapper options");
|
|
|
|
static cl::opt<object::OffloadKind> Kind(
|
|
"kind", cl::desc("Wrap for offload kind:"), cl::cat(OffloadWrapeprCategory),
|
|
cl::Required,
|
|
cl::values(clEnumValN(object::OFK_OpenMP, "openmp", "Wrap OpenMP binaries"),
|
|
clEnumValN(object::OFK_Cuda, "cuda", "Wrap CUDA binaries"),
|
|
clEnumValN(object::OFK_HIP, "hip", "Wrap HIP binaries")));
|
|
|
|
static cl::opt<std::string> OutputFile("o", cl::desc("Write output to <file>."),
|
|
cl::value_desc("file"),
|
|
cl::cat(OffloadWrapeprCategory));
|
|
|
|
static cl::list<std::string> InputFiles(cl::Positional,
|
|
cl::desc("Wrap input from <file>"),
|
|
cl::value_desc("file"), cl::OneOrMore,
|
|
cl::cat(OffloadWrapeprCategory));
|
|
|
|
static cl::opt<std::string>
|
|
TheTriple("triple", cl::desc("Target triple for the wrapper module"),
|
|
cl::init(sys::getDefaultTargetTriple()),
|
|
cl::cat(OffloadWrapeprCategory));
|
|
|
|
static Error wrapImages(ArrayRef<ArrayRef<char>> BuffersToWrap) {
|
|
if (BuffersToWrap.size() > 1 &&
|
|
(Kind == llvm::object::OFK_Cuda || Kind == llvm::object::OFK_HIP))
|
|
return createStringError(
|
|
"CUDA / HIP offloading uses a single fatbinary or offload bundle");
|
|
|
|
LLVMContext Context;
|
|
Module M("offload.wrapper.module", Context);
|
|
M.setTargetTriple(Triple());
|
|
|
|
switch (Kind) {
|
|
case llvm::object::OFK_OpenMP:
|
|
if (Error Err = offloading::wrapOpenMPBinaries(
|
|
M, BuffersToWrap, offloading::getOffloadEntryArray(M),
|
|
/*Suffix=*/"", /*Relocatable=*/false))
|
|
return Err;
|
|
break;
|
|
case llvm::object::OFK_Cuda:
|
|
if (Error Err = offloading::wrapCudaBinary(
|
|
M, BuffersToWrap.front(), offloading::getOffloadEntryArray(M),
|
|
/*Suffix=*/"", /*EmitSurfacesAndTextures=*/false))
|
|
return Err;
|
|
break;
|
|
case llvm::object::OFK_HIP:
|
|
if (Error Err = offloading::wrapHIPBinary(
|
|
M, BuffersToWrap.front(), offloading::getOffloadEntryArray(M)))
|
|
return Err;
|
|
break;
|
|
case llvm::object::OFK_SYCL:
|
|
if (Error Err = offloading::wrapSYCLBinaries(M, BuffersToWrap.front()))
|
|
return Err;
|
|
break;
|
|
default:
|
|
return createStringError(getOffloadKindName(Kind) +
|
|
" wrapping is not supported");
|
|
}
|
|
|
|
int FD = -1;
|
|
if (std::error_code EC = sys::fs::openFileForWrite(OutputFile, FD))
|
|
return errorCodeToError(EC);
|
|
llvm::raw_fd_ostream OS(FD, true);
|
|
WriteBitcodeToFile(M, OS);
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
InitLLVM X(argc, argv);
|
|
cl::HideUnrelatedOptions(OffloadWrapeprCategory);
|
|
cl::ParseCommandLineOptions(
|
|
argc, argv,
|
|
"Generate runtime registration code for a device binary image\n");
|
|
|
|
if (Help) {
|
|
cl::PrintHelpMessage();
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
auto ReportError = [argv](Error E) {
|
|
logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0]));
|
|
exit(EXIT_FAILURE);
|
|
};
|
|
|
|
SmallVector<std::unique_ptr<MemoryBuffer>> Buffers;
|
|
SmallVector<ArrayRef<char>> BuffersToWrap;
|
|
for (StringRef Input : InputFiles) {
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
|
|
MemoryBuffer::getFileOrSTDIN(Input);
|
|
if (std::error_code EC = BufferOrErr.getError())
|
|
ReportError(createFileError(Input, EC));
|
|
std::unique_ptr<MemoryBuffer> &Buffer =
|
|
Buffers.emplace_back(std::move(*BufferOrErr));
|
|
BuffersToWrap.emplace_back(
|
|
ArrayRef<char>(Buffer->getBufferStart(), Buffer->getBufferSize()));
|
|
}
|
|
|
|
if (Error Err = wrapImages(BuffersToWrap))
|
|
ReportError(std::move(Err));
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|