diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 | 
| commit | 145449b1e420787bb99721a429341fa6be3adfb6 (patch) | |
| tree | 1d56ae694a6de602e348dd80165cf881a36600ed /llvm/lib/Object/OffloadBinary.cpp | |
| parent | ecbca9f5fb7d7613d2b94982c4825eb0d33d6842 (diff) | |
Diffstat (limited to 'llvm/lib/Object/OffloadBinary.cpp')
| -rw-r--r-- | llvm/lib/Object/OffloadBinary.cpp | 164 | 
1 files changed, 164 insertions, 0 deletions
diff --git a/llvm/lib/Object/OffloadBinary.cpp b/llvm/lib/Object/OffloadBinary.cpp new file mode 100644 index 000000000000..21946ec2d6fb --- /dev/null +++ b/llvm/lib/Object/OffloadBinary.cpp @@ -0,0 +1,164 @@ +//===- Offloading.cpp - Utilities for handling offloading code  -*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/OffloadBinary.h" + +#include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/MC/StringTableBuilder.h" +#include "llvm/Object/Error.h" +#include "llvm/Support/Alignment.h" +#include "llvm/Support/FileOutputBuffer.h" + +using namespace llvm; +using namespace llvm::object; + +Expected<std::unique_ptr<OffloadBinary>> +OffloadBinary::create(MemoryBufferRef Buf) { +  if (Buf.getBufferSize() < sizeof(Header) + sizeof(Entry)) +    return errorCodeToError(object_error::parse_failed); + +  // Check for 0x10FF1OAD magic bytes. +  if (identify_magic(Buf.getBuffer()) != file_magic::offload_binary) +    return errorCodeToError(object_error::parse_failed); + +  // Make sure that the data has sufficient alignment. +  if (!isAddrAligned(Align(getAlignment()), Buf.getBufferStart())) +    return errorCodeToError(object_error::parse_failed); + +  const char *Start = Buf.getBufferStart(); +  const Header *TheHeader = reinterpret_cast<const Header *>(Start); +  if (TheHeader->Version != OffloadBinary::Version) +    return errorCodeToError(object_error::parse_failed); + +  if (TheHeader->Size > Buf.getBufferSize() || +      TheHeader->EntryOffset > TheHeader->Size - sizeof(Entry) || +      TheHeader->EntrySize > TheHeader->Size - sizeof(Header)) +    return errorCodeToError(object_error::unexpected_eof); + +  const Entry *TheEntry = +      reinterpret_cast<const Entry *>(&Start[TheHeader->EntryOffset]); + +  if (TheEntry->ImageOffset > Buf.getBufferSize() || +      TheEntry->StringOffset > Buf.getBufferSize()) +    return errorCodeToError(object_error::unexpected_eof); + +  return std::unique_ptr<OffloadBinary>( +      new OffloadBinary(Buf, TheHeader, TheEntry)); +} + +std::unique_ptr<MemoryBuffer> +OffloadBinary::write(const OffloadingImage &OffloadingData) { +  // Create a null-terminated string table with all the used strings. +  StringTableBuilder StrTab(StringTableBuilder::ELF); +  for (auto &KeyAndValue : OffloadingData.StringData) { +    StrTab.add(KeyAndValue.getKey()); +    StrTab.add(KeyAndValue.getValue()); +  } +  StrTab.finalize(); + +  uint64_t StringEntrySize = +      sizeof(StringEntry) * OffloadingData.StringData.size(); + +  // Make sure the image we're wrapping around is aligned as well. +  uint64_t BinaryDataSize = alignTo(sizeof(Header) + sizeof(Entry) + +                                        StringEntrySize + StrTab.getSize(), +                                    getAlignment()); + +  // Create the header and fill in the offsets. The entry will be directly +  // placed after the header in memory. Align the size to the alignment of the +  // header so this can be placed contiguously in a single section. +  Header TheHeader; +  TheHeader.Size = alignTo( +      BinaryDataSize + OffloadingData.Image->getBufferSize(), getAlignment()); +  TheHeader.EntryOffset = sizeof(Header); +  TheHeader.EntrySize = sizeof(Entry); + +  // Create the entry using the string table offsets. The string table will be +  // placed directly after the entry in memory, and the image after that. +  Entry TheEntry; +  TheEntry.TheImageKind = OffloadingData.TheImageKind; +  TheEntry.TheOffloadKind = OffloadingData.TheOffloadKind; +  TheEntry.Flags = OffloadingData.Flags; +  TheEntry.StringOffset = sizeof(Header) + sizeof(Entry); +  TheEntry.NumStrings = OffloadingData.StringData.size(); + +  TheEntry.ImageOffset = BinaryDataSize; +  TheEntry.ImageSize = OffloadingData.Image->getBufferSize(); + +  SmallVector<char> Data; +  Data.reserve(TheHeader.Size); +  raw_svector_ostream OS(Data); +  OS << StringRef(reinterpret_cast<char *>(&TheHeader), sizeof(Header)); +  OS << StringRef(reinterpret_cast<char *>(&TheEntry), sizeof(Entry)); +  for (auto &KeyAndValue : OffloadingData.StringData) { +    uint64_t Offset = sizeof(Header) + sizeof(Entry) + StringEntrySize; +    StringEntry Map{Offset + StrTab.getOffset(KeyAndValue.getKey()), +                    Offset + StrTab.getOffset(KeyAndValue.getValue())}; +    OS << StringRef(reinterpret_cast<char *>(&Map), sizeof(StringEntry)); +  } +  StrTab.write(OS); +  // Add padding to required image alignment. +  OS.write_zeros(TheEntry.ImageOffset - OS.tell()); +  OS << OffloadingData.Image->getBuffer(); + +  // Add final padding to required alignment. +  assert(TheHeader.Size >= OS.tell() && "Too much data written?"); +  OS.write_zeros(TheHeader.Size - OS.tell()); +  assert(TheHeader.Size == OS.tell() && "Size mismatch"); + +  return MemoryBuffer::getMemBufferCopy(OS.str()); +} + +OffloadKind object::getOffloadKind(StringRef Name) { +  return llvm::StringSwitch<OffloadKind>(Name) +      .Case("openmp", OFK_OpenMP) +      .Case("cuda", OFK_Cuda) +      .Case("hip", OFK_HIP) +      .Default(OFK_None); +} + +StringRef object::getOffloadKindName(OffloadKind Kind) { +  switch (Kind) { +  case OFK_OpenMP: +    return "openmp"; +  case OFK_Cuda: +    return "cuda"; +  case OFK_HIP: +    return "hip"; +  default: +    return "none"; +  } +} + +ImageKind object::getImageKind(StringRef Name) { +  return llvm::StringSwitch<ImageKind>(Name) +      .Case("o", IMG_Object) +      .Case("bc", IMG_Bitcode) +      .Case("cubin", IMG_Cubin) +      .Case("fatbin", IMG_Fatbinary) +      .Case("s", IMG_PTX) +      .Default(IMG_None); +} + +StringRef object::getImageKindName(ImageKind Kind) { +  switch (Kind) { +  case IMG_Object: +    return "o"; +  case IMG_Bitcode: +    return "bc"; +  case IMG_Cubin: +    return "cubin"; +  case IMG_Fatbinary: +    return "fatbin"; +  case IMG_PTX: +    return "s"; +  default: +    return ""; +  } +}  | 
