[llvm][offload] Change Intel's SPIRV wrapper from ELF to OffloadBinary (#185413)
Change SPIRV wrapping done in clang-linker-wrapper from custom ELF to OffloadBinary. Depends on: - #185404 (Accept OffloadBinary in liboffload & L0 plugin) Follow-up PRs: - #185425 (Adjusts llvm-objdump) - #184774 (Adjusts llvm-offload-binary) --------- Co-authored-by: Yury Plyakhin <yury.plyakhin@intel.com>
This commit is contained in:
parent
4f76d16203
commit
9348026ab4
@ -1,22 +0,0 @@
|
||||
// Verify the ELF packaging of OpenMP SPIR-V device images.
|
||||
// REQUIRES: system-linux
|
||||
// REQUIRES: spirv-tools
|
||||
// REQUIRES: spirv-registered-target
|
||||
// RUN: mkdir -p %t_tmp
|
||||
// RUN: cd %t_tmp
|
||||
// RUN: %clangxx -fopenmp -fopenmp-targets=spirv64-intel -nogpulib -c -o %t_clang-linker-wrapper-spirv-elf.o %s
|
||||
// RUN: not clang-linker-wrapper -o a.out %t_clang-linker-wrapper-spirv-elf.o --save-temps --linker-path=ld
|
||||
// RUN: llvm-offload-binary --image=triple=spirv64-intel,kind=openmp,file=%t.elf %t_tmp/a.out.openmp.image.wrapper.o
|
||||
// RUN: llvm-readelf -h %t.elf | FileCheck -check-prefix=CHECK-MACHINE %s
|
||||
// RUN: llvm-readelf -t %t.elf | FileCheck -check-prefix=CHECK-SECTION %s
|
||||
// RUN: llvm-readelf -n %t.elf | FileCheck -check-prefix=CHECK-NOTES %s
|
||||
|
||||
// CHECK-MACHINE: Machine: Intel Graphics Technology
|
||||
|
||||
// CHECK-SECTION: .note.inteloneompoffload
|
||||
// CHECK-SECTION: __openmp_offload_spirv_0
|
||||
|
||||
// CHECK-NOTES-COUNT-3: INTELONEOMPOFFLOAD
|
||||
int main(int argc, char** argv) {
|
||||
return 0;
|
||||
}
|
||||
@ -652,7 +652,7 @@ Error containerizeRawImage(std::unique_ptr<MemoryBuffer> &Img, OffloadKind Kind,
|
||||
llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
|
||||
if (Kind == OFK_OpenMP && Triple.isSPIRV() &&
|
||||
Triple.getVendor() == llvm::Triple::Intel)
|
||||
return offloading::intel::containerizeOpenMPSPIRVImage(Img);
|
||||
return offloading::intel::containerizeOpenMPSPIRVImage(Img, Triple);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
|
||||
@ -157,11 +157,34 @@ LLVM_ABI Error getAMDGPUMetaDataFromImage(
|
||||
uint16_t &ELFABIVersion);
|
||||
} // namespace amdgpu
|
||||
|
||||
/// Containerizes an image within an OffloadBinary image.
|
||||
/// Creates a nested OffloadBinary structure where the inner binary contains
|
||||
/// the raw image and associated metadata (version, format, triple, etc.).
|
||||
/// \param Binary The image to containerize.
|
||||
/// \param Triple The target triple to be associated with the image.
|
||||
/// \param ImageKind The format of the image, e.g. SPIR-V or CUBIN.
|
||||
/// \param OffloadKind The expected consuming runtime of the image, e.g. CUDA or
|
||||
/// OpenMP.
|
||||
/// \param ImageFlags Flags associated with the image, e.g. for AMDGPU the
|
||||
/// features.
|
||||
/// \param MetaData The key-value map of metadata to be associated with the
|
||||
/// image.
|
||||
LLVM_ABI Error containerizeImage(std::unique_ptr<MemoryBuffer> &Binary,
|
||||
llvm::Triple Triple,
|
||||
object::ImageKind ImageKind,
|
||||
object::OffloadKind OffloadKind,
|
||||
int32_t ImageFlags,
|
||||
MapVector<StringRef, StringRef> &MetaData);
|
||||
|
||||
namespace intel {
|
||||
/// Containerizes an offloading binary into the ELF binary format expected by
|
||||
/// the Intel runtime offload plugin.
|
||||
LLVM_ABI Error
|
||||
containerizeOpenMPSPIRVImage(std::unique_ptr<MemoryBuffer> &Binary);
|
||||
/// Containerizes an OpenMP SPIR-V image into an OffloadBinary image.
|
||||
/// \param Binary The SPIR-V binary to containerize.
|
||||
/// \param Triple The target triple to be associated with the image.
|
||||
/// \param CompileOpts Optional compilation options.
|
||||
/// \param LinkOpts Optional linking options.
|
||||
LLVM_ABI Error containerizeOpenMPSPIRVImage(
|
||||
std::unique_ptr<MemoryBuffer> &Binary, llvm::Triple Triple,
|
||||
StringRef CompileOpts = "", StringRef LinkOpts = "");
|
||||
} // namespace intel
|
||||
} // namespace offloading
|
||||
} // namespace llvm
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
#include "llvm/IR/GlobalVariable.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Object/ELFObjectFile.h"
|
||||
#include "llvm/Object/OffloadBinary.h"
|
||||
#include "llvm/ObjectYAML/ELFYAML.h"
|
||||
#include "llvm/ObjectYAML/yaml2obj.h"
|
||||
#include "llvm/Support/MemoryBufferRef.h"
|
||||
@ -377,84 +378,49 @@ Error llvm::offloading::amdgpu::getAMDGPUMetaDataFromImage(
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
Error offloading::intel::containerizeOpenMPSPIRVImage(
|
||||
std::unique_ptr<MemoryBuffer> &Img) {
|
||||
constexpr char INTEL_ONEOMP_OFFLOAD_VERSION[] = "1.0";
|
||||
constexpr int NT_INTEL_ONEOMP_OFFLOAD_VERSION = 1;
|
||||
constexpr int NT_INTEL_ONEOMP_OFFLOAD_IMAGE_COUNT = 2;
|
||||
constexpr int NT_INTEL_ONEOMP_OFFLOAD_IMAGE_AUX = 3;
|
||||
|
||||
// Start creating notes for the ELF container.
|
||||
std::vector<ELFYAML::NoteEntry> Notes;
|
||||
std::string Version = toHex(INTEL_ONEOMP_OFFLOAD_VERSION);
|
||||
Notes.emplace_back(ELFYAML::NoteEntry{"INTELONEOMPOFFLOAD",
|
||||
yaml::BinaryRef(Version),
|
||||
NT_INTEL_ONEOMP_OFFLOAD_VERSION});
|
||||
Error offloading::containerizeImage(std::unique_ptr<MemoryBuffer> &Img,
|
||||
llvm::Triple Triple,
|
||||
object::ImageKind ImageKind,
|
||||
object::OffloadKind OffloadKind,
|
||||
int32_t ImageFlags,
|
||||
MapVector<StringRef, StringRef> &MetaData) {
|
||||
using namespace object;
|
||||
|
||||
// The AuxInfo string will hold auxiliary information for the image.
|
||||
// ELFYAML::NoteEntry structures will hold references to the
|
||||
// string, so we have to make sure the string is valid.
|
||||
std::string AuxInfo;
|
||||
// Create inner OffloadBinary containing the raw image.
|
||||
OffloadBinary::OffloadingImage InnerImage;
|
||||
InnerImage.TheImageKind = ImageKind;
|
||||
InnerImage.TheOffloadKind = OffloadKind;
|
||||
InnerImage.Flags = ImageFlags;
|
||||
|
||||
// TODO: Pass compile/link opts
|
||||
StringRef CompileOpts = "";
|
||||
StringRef LinkOpts = "";
|
||||
InnerImage.StringData["triple"] = Triple.getTriple();
|
||||
for (const auto &[Key, Value] : MetaData)
|
||||
InnerImage.StringData[Key] = Value;
|
||||
|
||||
unsigned ImageFmt = 1; // SPIR-V format
|
||||
InnerImage.Image = std::move(Img);
|
||||
|
||||
AuxInfo = toHex((Twine(0) + Twine('\0') + Twine(ImageFmt) + Twine('\0') +
|
||||
CompileOpts + Twine('\0') + LinkOpts)
|
||||
.str());
|
||||
Notes.emplace_back(ELFYAML::NoteEntry{"INTELONEOMPOFFLOAD",
|
||||
yaml::BinaryRef(AuxInfo),
|
||||
NT_INTEL_ONEOMP_OFFLOAD_IMAGE_AUX});
|
||||
SmallString<0> InnerBinaryData = OffloadBinary::write(InnerImage);
|
||||
|
||||
std::string ImgCount = toHex(Twine(1).str()); // always one image per ELF
|
||||
Notes.emplace_back(ELFYAML::NoteEntry{"INTELONEOMPOFFLOAD",
|
||||
yaml::BinaryRef(ImgCount),
|
||||
NT_INTEL_ONEOMP_OFFLOAD_IMAGE_COUNT});
|
||||
|
||||
std::string YamlFile;
|
||||
llvm::raw_string_ostream YamlFileStream(YamlFile);
|
||||
|
||||
// Write the YAML template file.
|
||||
|
||||
// We use 64-bit little-endian ELF currently.
|
||||
ELFYAML::FileHeader Header{};
|
||||
Header.Class = ELF::ELFCLASS64;
|
||||
Header.Data = ELF::ELFDATA2LSB;
|
||||
Header.Type = ELF::ET_DYN;
|
||||
Header.Machine = ELF::EM_INTELGT;
|
||||
|
||||
// Create a section with notes.
|
||||
ELFYAML::NoteSection Section{};
|
||||
Section.Type = ELF::SHT_NOTE;
|
||||
Section.AddressAlign = 0;
|
||||
Section.Name = ".note.inteloneompoffload";
|
||||
Section.Notes.emplace(std::move(Notes));
|
||||
|
||||
ELFYAML::Object Object{};
|
||||
Object.Header = Header;
|
||||
Object.Chunks.push_back(
|
||||
std::make_unique<ELFYAML::NoteSection>(std::move(Section)));
|
||||
|
||||
// Create the section that will hold the image
|
||||
ELFYAML::RawContentSection ImageSection{};
|
||||
ImageSection.Type = ELF::SHT_PROGBITS;
|
||||
ImageSection.AddressAlign = 0;
|
||||
std::string Name = "__openmp_offload_spirv_0";
|
||||
ImageSection.Name = Name;
|
||||
ImageSection.Content =
|
||||
llvm::yaml::BinaryRef(arrayRefFromStringRef(Img->getBuffer()));
|
||||
Object.Chunks.push_back(
|
||||
std::make_unique<ELFYAML::RawContentSection>(std::move(ImageSection)));
|
||||
Error Err = Error::success();
|
||||
llvm::yaml::yaml2elf(
|
||||
Object, YamlFileStream,
|
||||
[&Err](const Twine &Msg) { Err = createStringError(Msg); }, UINT64_MAX);
|
||||
if (Err)
|
||||
return Err;
|
||||
|
||||
Img = MemoryBuffer::getMemBufferCopy(YamlFile);
|
||||
Img = MemoryBuffer::getMemBufferCopy(InnerBinaryData);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error offloading::intel::containerizeOpenMPSPIRVImage(
|
||||
std::unique_ptr<MemoryBuffer> &Binary, llvm::Triple Triple,
|
||||
StringRef CompileOpts, StringRef LinkOpts) {
|
||||
constexpr char INTEL_ONEOMP_OFFLOAD_VERSION[] = "1.0";
|
||||
|
||||
assert(Triple.isSPIRV() && Triple.getVendor() == llvm::Triple::Intel &&
|
||||
"Expected SPIR-V triple with Intel vendor");
|
||||
|
||||
MapVector<StringRef, StringRef> MetaData;
|
||||
MetaData["version"] = INTEL_ONEOMP_OFFLOAD_VERSION;
|
||||
if (!CompileOpts.empty())
|
||||
MetaData["compile-opts"] = CompileOpts;
|
||||
if (!LinkOpts.empty())
|
||||
MetaData["link-opts"] = LinkOpts;
|
||||
|
||||
return containerizeImage(Binary, Triple, object::ImageKind::IMG_SPIRV,
|
||||
object::OffloadKind::OFK_OpenMP, /*ImageFlags=*/0,
|
||||
MetaData);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user