llvm-project/llvm/tools/llvm-offload-wrapper/llvm-offload-wrapper.cpp
Maksim Sabianin 65d730b4a5
[SYCL] Add offload wrapping for SYCL kind (#147508)
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++.
2025-09-26 17:02:31 +00:00

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;
}