jhuber6 updated this revision to Diff 416749.
jhuber6 added a comment.
Changing to add alignment to the global variable. Should ensure that the section
alignment is correct.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D122069/new/
https://reviews.llvm.org/D122069
Files:
clang/include/clang/Basic/CodeGenOptions.h
clang/include/clang/Basic/Offloading.h
clang/lib/Basic/CMakeLists.txt
clang/lib/Basic/Offloading.cpp
clang/lib/CodeGen/BackendUtil.cpp
clang/lib/Driver/ToolChains/Clang.cpp
clang/test/Driver/openmp-offload-gpu.c
clang/test/Frontend/embed-object.c
clang/test/Frontend/embed-object.ll
clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
llvm/include/llvm/Transforms/Utils/ModuleUtils.h
llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
llvm/lib/Transforms/Utils/ModuleUtils.cpp
Index: llvm/lib/Transforms/Utils/ModuleUtils.cpp
===================================================================
--- llvm/lib/Transforms/Utils/ModuleUtils.cpp
+++ llvm/lib/Transforms/Utils/ModuleUtils.cpp
@@ -265,15 +265,15 @@
}
void llvm::embedBufferInModule(Module &M, MemoryBufferRef Buf,
- StringRef SectionName) {
- // Embed the buffer into the module.
+ StringRef SectionName, Align Alignment) {
+ // Embed the memory buffer into the module.
Constant *ModuleConstant = ConstantDataArray::get(
M.getContext(), makeArrayRef(Buf.getBufferStart(), Buf.getBufferSize()));
GlobalVariable *GV = new GlobalVariable(
- M, ModuleConstant->getType(), true, GlobalValue::ExternalLinkage,
- ModuleConstant, SectionName.drop_front());
+ M, ModuleConstant->getType(), true, GlobalValue::PrivateLinkage,
+ ModuleConstant, "llvm.embedded.object");
GV->setSection(SectionName);
- GV->setVisibility(GlobalValue::HiddenVisibility);
+ GV->setAlignment(Alignment);
appendToCompilerUsed(M, GV);
}
Index: llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
===================================================================
--- llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -447,7 +447,7 @@
Name == getInstrProfSectionName(IPSK_covfun, Triple::ELF,
/*AddSegmentInfo=*/false) ||
Name == ".llvmbc" || Name == ".llvmcmd" ||
- Name.startswith(".llvm.offloading."))
+ Name.startswith(".llvm.offloading"))
return SectionKind::getMetadata();
if (Name.empty() || Name[0] != '.') return K;
Index: llvm/include/llvm/Transforms/Utils/ModuleUtils.h
===================================================================
--- llvm/include/llvm/Transforms/Utils/ModuleUtils.h
+++ llvm/include/llvm/Transforms/Utils/ModuleUtils.h
@@ -14,6 +14,7 @@
#define LLVM_TRANSFORMS_UTILS_MODULEUTILS_H
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Alignment.h"
#include "llvm/Support/MemoryBufferRef.h"
#include <utility> // for std::pair
@@ -109,7 +110,8 @@
/// Embed the memory buffer \p Buf into the module \p M as a global using the
/// specified section name.
-void embedBufferInModule(Module &M, MemoryBufferRef Buf, StringRef SectionName);
+void embedBufferInModule(Module &M, MemoryBufferRef Buf, StringRef SectionName,
+ Align Alignment = Align(1));
class CallInst;
namespace VFABI {
Index: clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
===================================================================
--- clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -15,6 +15,7 @@
//===---------------------------------------------------------------------===//
#include "OffloadWrapper.h"
+#include "clang/Basic/Offloading.h"
#include "clang/Basic/Version.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Bitcode/BitcodeWriter.h"
@@ -47,6 +48,7 @@
#include "llvm/Target/TargetMachine.h"
using namespace llvm;
+using namespace clang;
using namespace llvm::object;
static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
@@ -146,9 +148,10 @@
static codegen::RegisterCodeGenFlags CodeGenFlags;
/// Magic section string that marks the existence of offloading data. The
-/// section string will be formatted as `.llvm.offloading.<triple>.<arch>`.
-#define OFFLOAD_SECTION_MAGIC_STR ".llvm.offloading."
+/// section will contain one or more offloading binaries stored contiguously.
+#define OFFLOAD_SECTION_MAGIC_STR ".llvm.offloading"
+// TODO: Replace all uses of DeviceFile with OffloadFile.
/// Information for a device offloading file extracted from the host.
struct DeviceFile {
DeviceFile(StringRef Kind, StringRef TheTriple, StringRef Arch,
@@ -201,16 +204,6 @@
llvm::errs() << *IC << (std::next(IC) != IE ? " " : "\n");
}
-static StringRef getDeviceFileExtension(StringRef DeviceTriple,
- bool IsBitcode = false) {
- Triple TheTriple(DeviceTriple);
- if (TheTriple.isAMDGPU() || IsBitcode)
- return "bc";
- if (TheTriple.isNVPTX())
- return "cubin";
- return "o";
-}
-
std::string getMainExecutable(const char *Name) {
void *Ptr = (void *)(intptr_t)&getMainExecutable;
auto COWPath = sys::fs::getMainExecutable(Name, Ptr);
@@ -296,39 +289,50 @@
StringRef Prefix = sys::path::stem(Obj.getFileName());
SmallVector<StringRef, 4> ToBeStripped;
- // Extract data from sections of the form `.llvm.offloading.<triple>.<arch>`.
+ // Extract offloading binaries from sections with the name `.llvm.offloading`.
for (const SectionRef &Sec : Obj.sections()) {
Expected<StringRef> Name = Sec.getName();
- if (!Name || !Name->startswith(OFFLOAD_SECTION_MAGIC_STR))
+ if (!Name || !Name->equals(OFFLOAD_SECTION_MAGIC_STR))
continue;
- SmallVector<StringRef, 4> SectionFields;
- Name->split(SectionFields, '.');
- StringRef Kind = SectionFields[3];
- StringRef DeviceTriple = SectionFields[4];
- StringRef Arch = SectionFields[5];
+ Expected<StringRef> Contents = Sec.getContents();
+ if (!Contents)
+ return Contents.takeError();
+
+ uint64_t Offset = 0;
+ // There could be multiple offloading binaries stored at this section.
+ while (Offset < Contents->size()) {
+ std::unique_ptr<MemoryBuffer> Buffer =
+ MemoryBuffer::getMemBuffer(Contents->drop_front(Offset), *Name,
+ /*RequiresNullTerminator*/ false);
+ auto BinaryOrErr = OffloadBinary::create(*Buffer);
+ if (!BinaryOrErr)
+ return BinaryOrErr.takeError();
+ OffloadBinary &Binary = **BinaryOrErr;
+
+ StringRef Kind =
+ getOffloadKindName(static_cast<OffloadKind>(Binary.getOffloadKind()));
+ StringRef Suffix =
+ getImageKindName(static_cast<ImageKind>(Binary.getImageKind()));
- if (Expected<StringRef> Contents = Sec.getContents()) {
SmallString<128> TempFile;
- StringRef DeviceExtension = getDeviceFileExtension(
- DeviceTriple, identify_magic(*Contents) == file_magic::bitcode);
if (Error Err = createOutputFile(Prefix + "-" + Kind + "-" +
- DeviceTriple + "-" + Arch,
- DeviceExtension, TempFile))
+ Binary.getTripleStr() + "-" +
+ Binary.getArch(),
+ Suffix, TempFile))
return std::move(Err);
- Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr =
- FileOutputBuffer::create(TempFile, Sec.getSize());
- if (!OutputOrErr)
- return OutputOrErr.takeError();
- std::unique_ptr<FileOutputBuffer> Output = std::move(*OutputOrErr);
- std::copy(Contents->begin(), Contents->end(), Output->getBufferStart());
- if (Error E = Output->commit())
- return std::move(E);
-
- DeviceFiles.emplace_back(Kind, DeviceTriple, Arch, TempFile);
- ToBeStripped.push_back(*Name);
+ Expected<OffloadFile> File = Binary.createOffloadFile(TempFile);
+ if (!File)
+ return File.takeError();
+
+ DeviceFiles.emplace_back(Kind, File->TheTriple, File->Arch,
+ File->Filename);
+
+ Offset += Binary.getSize();
}
+
+ ToBeStripped.push_back(*Name);
}
if (ToBeStripped.empty() || !StripSections)
@@ -405,42 +409,50 @@
SmallVector<GlobalVariable *, 4> ToBeDeleted;
- // Extract data from the global string containing a section of the form
- // `.llvm.offloading.<triple>.<arch>`.
+ // Extract offloading data from globals with the `.llvm.offloading` section
+ // name.
for (GlobalVariable &GV : M->globals()) {
- if (!GV.hasSection() ||
- !GV.getSection().startswith(OFFLOAD_SECTION_MAGIC_STR))
+ if (!GV.hasSection() || !GV.getSection().equals(OFFLOAD_SECTION_MAGIC_STR))
continue;
auto *CDS = dyn_cast<ConstantDataSequential>(GV.getInitializer());
if (!CDS)
continue;
- SmallVector<StringRef, 4> SectionFields;
- GV.getSection().split(SectionFields, '.');
- StringRef Kind = SectionFields[3];
- StringRef DeviceTriple = SectionFields[4];
- StringRef Arch = SectionFields[5];
-
StringRef Contents = CDS->getAsString();
- SmallString<128> TempFile;
- StringRef DeviceExtension = getDeviceFileExtension(
- DeviceTriple, identify_magic(Contents) == file_magic::bitcode);
- if (Error Err = createOutputFile(Prefix + "-" + Kind + "-" + DeviceTriple +
- "-" + Arch,
- DeviceExtension, TempFile))
- return std::move(Err);
- Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr =
- FileOutputBuffer::create(TempFile, Contents.size());
- if (!OutputOrErr)
- return OutputOrErr.takeError();
- std::unique_ptr<FileOutputBuffer> Output = std::move(*OutputOrErr);
- std::copy(Contents.begin(), Contents.end(), Output->getBufferStart());
- if (Error E = Output->commit())
- return std::move(E);
+ uint64_t Offset = 0;
+ // There could be multiple offloading binaries stored at this section.
+ while (Offset < Contents.size()) {
+ std::unique_ptr<MemoryBuffer> Buffer =
+ MemoryBuffer::getMemBuffer(Contents.drop_front(Offset), GV.getName(),
+ /*RequiresNullTerminator*/ false);
+ auto BinaryOrErr = OffloadBinary::create(*Buffer);
+ if (!BinaryOrErr)
+ return BinaryOrErr.takeError();
+ OffloadBinary &Binary = **BinaryOrErr;
+
+ StringRef Kind =
+ getOffloadKindName(static_cast<OffloadKind>(Binary.getOffloadKind()));
+ StringRef Suffix =
+ getImageKindName(static_cast<ImageKind>(Binary.getImageKind()));
+
+ SmallString<128> TempFile;
+ if (Error Err = createOutputFile(Prefix + "-" + Kind + "-" +
+ Binary.getTripleStr() + "-" +
+ Binary.getArch(),
+ Suffix, TempFile))
+ return std::move(Err);
- DeviceFiles.emplace_back(Kind, DeviceTriple, Arch, TempFile);
+ Expected<OffloadFile> File = Binary.createOffloadFile(TempFile);
+ if (!File)
+ return File.takeError();
+
+ DeviceFiles.emplace_back(Kind, File->TheTriple, File->Arch,
+ File->Filename);
+
+ Offset += Binary.getSize();
+ }
ToBeDeleted.push_back(&GV);
}
Index: clang/test/Frontend/embed-object.ll
===================================================================
--- clang/test/Frontend/embed-object.ll
+++ clang/test/Frontend/embed-object.ll
@@ -1,11 +1,9 @@
; RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm \
-; RUN: -fembed-offload-object=%S/Inputs/empty.h,section1 \
-; RUN: -fembed-offload-object=%S/Inputs/empty.h,section2 -x ir %s -o - \
+; RUN: -fembed-offload-object=file=%S/Inputs/empty.h -x ir %s -o - \
; RUN: | FileCheck %s -check-prefix=CHECK
-; CHECK: @[[OBJECT1:.+]] = hidden constant [0 x i8] zeroinitializer, section ".llvm.offloading.section1"
-; CHECK: @[[OBJECT2:.+]] = hidden constant [0 x i8] zeroinitializer, section ".llvm.offloading.section2"
-; CHECK: @llvm.compiler.used = appending global [3 x i8*] [i8* @x, i8* getelementptr inbounds ([0 x i8], [0 x i8]* @[[OBJECT1]], i32 0, i32 0), i8* getelementptr inbounds ([0 x i8], [0 x i8]* @[[OBJECT2]], i32 0, i32 0)], section "llvm.metadata"
+; CHECK: @[[OBJECT:.+]] = private constant [88 x i8] c"\10\FF\10\AD{{.*}}\00", section ".llvm.offloading", align 8
+; CHECK: @llvm.compiler.used = appending global [2 x i8*] [i8* @x, i8* getelementptr inbounds ([88 x i8], [88 x i8]* @[[OBJECT]], i32 0, i32 0)], section "llvm.metadata"
@x = private constant i8 1
@llvm.compiler.used = appending global [1 x i8*] [i8* @x], section "llvm.metadata"
Index: clang/test/Frontend/embed-object.c
===================================================================
--- clang/test/Frontend/embed-object.c
+++ clang/test/Frontend/embed-object.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -x c -triple x86_64-unknown-linux-gnu -emit-llvm -fembed-offload-object=%S/Inputs/empty.h,section
+// RUN: %clang_cc1 -x c -triple x86_64-unknown-linux-gnu -emit-llvm -fembed-offload-object=file=%S/Inputs/empty.h -o - | FileCheck %s
-// CHECK: @[[OBJECT:.+]] = private constant [0 x i8] zeroinitializer, section ".llvm.offloading.section"
-// CHECK: @llvm.compiler.used = appending global [3 x i8*] [i8* getelementptr inbounds ([0 x i8], [0 x i8]* @[[OBJECT1]]], section "llvm.metadata"
+// CHECK: @[[OBJECT:.+]] = private constant [88 x i8] c"\10\FF\10\AD\01{{.*}}\00\00", section ".llvm.offloading", align 8
+// CHECK: @llvm.compiler.used = appending global [1 x i8*] [i8* getelementptr inbounds ([88 x i8], [88 x i8]* @[[OBJECT]], i32 0, i32 0)], section "llvm.metadata"
void foo(void) {}
Index: clang/test/Driver/openmp-offload-gpu.c
===================================================================
--- clang/test/Driver/openmp-offload-gpu.c
+++ clang/test/Driver/openmp-offload-gpu.c
@@ -345,4 +345,4 @@
// RUN: -fopenmp-new-driver -no-canonical-prefixes -nogpulib %s -o openmp-offload-gpu 2>&1 \
// RUN: | FileCheck -check-prefix=NEW_DRIVER_EMBEDDING %s
-// NEW_DRIVER_EMBEDDING: -fembed-offload-object=[[CUBIN:.*\.cubin]],openmp.nvptx64-nvidia-cuda.sm_70
+// NEW_DRIVER_EMBEDDING: -fembed-offload-object=file=[[CUBIN:.*\.cubin]],kind=openmp,triple=nvptx64-nvidia-cuda,arch=sm_70
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -6974,13 +6974,12 @@
const ArgList &TCArgs = C.getArgsForToolChain(TC, "", Action::OFK_OpenMP);
StringRef File =
C.getArgs().MakeArgString(TC->getInputFilename(*InputFile));
- StringRef InputName = Clang::getBaseInputStem(Args, Inputs);
CmdArgs.push_back(Args.MakeArgString(
- "-fembed-offload-object=" + File + "," +
- Action::GetOffloadKindName(Action::OFK_OpenMP) + "." +
- TC->getTripleString() + "." +
- TCArgs.getLastArgValue(options::OPT_march_EQ) + "." + InputName));
+ "-fembed-offload-object=file=" + File + "," +
+ "kind=" + Action::GetOffloadKindName(Action::OFK_OpenMP) + "," +
+ "triple=" + TC->getTripleString() + "," +
+ "arch=" + TCArgs.getLastArgValue(options::OPT_march_EQ)));
}
}
Index: clang/lib/CodeGen/BackendUtil.cpp
===================================================================
--- clang/lib/CodeGen/BackendUtil.cpp
+++ clang/lib/CodeGen/BackendUtil.cpp
@@ -10,6 +10,7 @@
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/Offloading.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/Utils.h"
@@ -1761,22 +1762,36 @@
return;
for (StringRef OffloadObject : CGOpts.OffloadObjects) {
- if (OffloadObject.count(',') != 1)
- Diags.Report(Diags.getCustomDiagID(
- DiagnosticsEngine::Error, "Invalid string pair for embedding '%0'"))
- << OffloadObject;
- auto FilenameAndSection = OffloadObject.split(',');
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ObjectOrErr =
- llvm::MemoryBuffer::getFileOrSTDIN(FilenameAndSection.first);
- if (std::error_code EC = ObjectOrErr.getError()) {
- auto DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "could not open '%0' for embedding");
- Diags.Report(DiagID) << FilenameAndSection.first;
+ StringMap<StringRef> Fields;
+ SmallVector<StringRef, 4> ObjectFields;
+ OffloadObject.split(ObjectFields, ',');
+
+ for (StringRef Field : ObjectFields) {
+ auto KeyAndValue = Field.split('=');
+ Fields[KeyAndValue.first] = KeyAndValue.second;
+ }
+
+ // Fill the offload file descriptor with the provided metadata. If this gets
+ // any more complicated it should be moved to its own clang tool.
+ OffloadFile File{};
+ File.Filename = Fields["file"].str();
+ File.TheOffloadKind = getOffloadKind(Fields["kind"]);
+ File.TheImageKind = getImageKind(Fields["file"].rsplit(".").second);
+ File.TheTriple = Fields["triple"].str();
+ File.Arch = Fields["arch"].str();
+ File.Features = Fields["features"].str();
+ File.CmdLine = Fields["cmdline"].str();
+
+ Expected<std::unique_ptr<MemoryBuffer>> BufferOrErr =
+ OffloadBinary::write(File);
+ if (!BufferOrErr) {
+ auto DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error, "Could not embed offload object: '%0'");
+ Diags.Report(DiagID) << BufferOrErr.takeError();
return;
}
- SmallString<128> SectionName(
- {".llvm.offloading.", FilenameAndSection.second});
- llvm::embedBufferInModule(*M, **ObjectOrErr, SectionName);
+ llvm::embedBufferInModule(*M, **BufferOrErr, ".llvm.offloading",
+ Align(OffloadBinary::getAlignment()));
}
}
Index: clang/lib/Basic/Offloading.cpp
===================================================================
--- /dev/null
+++ clang/lib/Basic/Offloading.cpp
@@ -0,0 +1,166 @@
+//===- 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 "clang/Basic/Offloading.h"
+
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Support/FileOutputBuffer.h"
+
+using namespace llvm;
+
+namespace clang {
+
+Expected<std::unique_ptr<OffloadBinary>>
+OffloadBinary::create(MemoryBufferRef Buffer) {
+ if (Buffer.getBufferSize() < sizeof(Header) + sizeof(Entry))
+ return createStringError(inconvertibleErrorCode(), "Invalid size");
+
+ // Check for 0x10FF1OAD magic bytes.
+ if (!Buffer.getBuffer().startswith("\x10\xff\x10\xad"))
+ return createStringError(inconvertibleErrorCode(),
+ "Offloading section missing magic bytes");
+
+ const char *Start = Buffer.getBufferStart();
+ const Header *TheHeader = reinterpret_cast<const Header *>(Start);
+ const Entry *TheEntry =
+ reinterpret_cast<const Entry *>(&Start[TheHeader->EntryOffset]);
+
+ return std::unique_ptr<OffloadBinary>(
+ new OffloadBinary(Buffer, TheHeader, TheEntry));
+}
+
+Expected<std::unique_ptr<MemoryBuffer>>
+OffloadBinary::write(OffloadFile &File) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ImageOrErr =
+ llvm::MemoryBuffer::getFileOrSTDIN(File.Filename);
+ if (std::error_code EC = ImageOrErr.getError())
+ return createFileError(File.Filename, EC);
+
+ MemoryBufferRef Image = **ImageOrErr;
+
+ // Create a string table with all the used strings.
+ StringTableBuilder StrTab(StringTableBuilder::ELF);
+ StrTab.add(File.TheTriple);
+ StrTab.add(File.Arch);
+ StrTab.add(File.Features);
+ StrTab.add(File.CmdLine);
+ StrTab.finalize();
+
+ // 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.Version = 1;
+ TheHeader.Size = alignTo(sizeof(Header) + sizeof(Entry) +
+ Image.getBufferSize() + StrTab.getSize(),
+ alignof(Header));
+ TheHeader.EntryOffset = sizeof(Header);
+
+ // 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.ImageKind = File.TheImageKind;
+ TheEntry.OffloadKind = File.TheOffloadKind;
+ TheEntry.Flags = File.Flags;
+
+ TheEntry.TripleOffset =
+ sizeof(Header) + sizeof(Entry) + StrTab.getOffset(File.TheTriple);
+ TheEntry.ArchOffset =
+ sizeof(Header) + sizeof(Entry) + StrTab.getOffset(File.Arch);
+ TheEntry.FeaturesOffset =
+ sizeof(Header) + sizeof(Entry) + StrTab.getOffset(File.Features);
+ TheEntry.CmdLineOffset =
+ sizeof(Header) + sizeof(Entry) + StrTab.getOffset(File.CmdLine);
+ TheEntry.ImageOffset = sizeof(Header) + sizeof(Entry) + StrTab.getSize();
+ TheEntry.ImageSize = Image.getBufferSize();
+
+ SmallVector<char, 256> Data;
+ raw_svector_ostream OS(Data);
+ OS << StringRef(reinterpret_cast<char *>(&TheHeader), sizeof(Header));
+ OS << StringRef(reinterpret_cast<char *>(&TheEntry), sizeof(Entry));
+ StrTab.write(OS);
+ OS << 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());
+}
+
+Expected<OffloadFile> OffloadBinary::createOffloadFile(StringRef Filename) {
+ ImageKind TheImageKind = static_cast<ImageKind>(getImageKind());
+ OffloadKind TheOffloadKind = static_cast<OffloadKind>(getOffloadKind());
+
+ // Write the device image data to the provided filename.
+ Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr =
+ FileOutputBuffer::create(Filename, getImage().size());
+ if (!OutputOrErr)
+ return OutputOrErr.takeError();
+ std::unique_ptr<FileOutputBuffer> Output = std::move(*OutputOrErr);
+ std::copy(getImage().bytes_begin(), getImage().bytes_end(),
+ Output->getBufferStart());
+ if (Error E = Output->commit())
+ return std::move(E);
+
+ return OffloadFile{TheImageKind, TheOffloadKind, getFlags(),
+ getTripleStr().str(), getArch().str(), getFeatures().str(),
+ getCmdLine().str(), Filename.str()};
+}
+
+OffloadKind getOffloadKind(StringRef Name) {
+ return llvm::StringSwitch<OffloadKind>(Name)
+ .Case("openmp", OFK_OpenMP)
+ .Case("cuda", OFK_Cuda)
+ .Case("hip", OFK_HIP)
+ .Default(OFK_None);
+}
+
+StringRef getOffloadKindName(OffloadKind Kind) {
+ switch (Kind) {
+ case OFK_OpenMP:
+ return "openmp";
+ case OFK_Cuda:
+ return "cuda";
+ case OFK_HIP:
+ return "hip";
+ default:
+ return "none";
+ }
+}
+
+ImageKind 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 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 "";
+ }
+}
+
+} // namespace clang
Index: clang/lib/Basic/CMakeLists.txt
===================================================================
--- clang/lib/Basic/CMakeLists.txt
+++ clang/lib/Basic/CMakeLists.txt
@@ -1,5 +1,6 @@
set(LLVM_LINK_COMPONENTS
Support
+ MC
)
find_first_existing_vc_file("${LLVM_MAIN_SRC_DIR}" llvm_vc)
@@ -43,6 +44,7 @@
CharInfo.cpp
CodeGenOptions.cpp
Cuda.cpp
+ Offloading.cpp
DarwinSDKInfo.cpp
Diagnostic.cpp
DiagnosticIDs.cpp
Index: clang/include/clang/Basic/Offloading.h
===================================================================
--- /dev/null
+++ clang/include/clang/Basic/Offloading.h
@@ -0,0 +1,130 @@
+//===--- Offloading.h - 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_OFFLOADING_H
+#define LLVM_CLANG_BASIC_OFFLOADING_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
+
+using llvm::Expected;
+using llvm::MemoryBuffer;
+using llvm::MemoryBufferRef;
+using llvm::StringRef;
+using llvm::Twine;
+
+namespace clang {
+
+/// The producer of the offloading action associated with the image.
+enum OffloadKind : uint16_t {
+ OFK_None = 0,
+ OFK_OpenMP,
+ OFK_Cuda,
+ OFK_HIP,
+};
+
+/// The type of contents the offloading image contains.
+enum ImageKind : uint16_t {
+ IMG_None = 0,
+ IMG_Object,
+ IMG_Bitcode,
+ IMG_Cubin,
+ IMG_Fatbinary,
+ IMG_PTX,
+};
+
+/// A generic struct for metadata associated with an offloading file. We need to
+/// associate metadata with an offloading file so we can properly identify it
+/// during the linking phase.
+struct OffloadFile {
+ ImageKind TheImageKind;
+ OffloadKind TheOffloadKind;
+ uint32_t Flags;
+
+ std::string TheTriple; // The target triple associated with this image.
+ std::string Arch; // The target architecture associated with this image.
+ std::string Features; // Associated target features.
+ std::string CmdLine; // Associated command line arguments (e.g. cuda-path).
+ std::string Filename; // The filename containing the image data.
+};
+
+/// A simple binary serialization of an offloading file. We use this format to
+/// embed the offloading image into the host executable so it can be extracted
+/// and used by the linker.
+class OffloadBinary {
+public:
+ static Expected<std::unique_ptr<OffloadBinary>> create(MemoryBufferRef Data);
+
+ static Expected<std::unique_ptr<MemoryBuffer>> write(OffloadFile &File);
+
+ static uint64_t getAlignment() { return alignof(Header); }
+
+ uint16_t getImageKind() const { return TheEntry->ImageKind; }
+ uint16_t getOffloadKind() const { return TheEntry->OffloadKind; }
+ uint32_t getFlags() const { return TheEntry->Flags; }
+ uint64_t getSize() const { return TheHeader->Size; }
+
+ StringRef getTripleStr() const { return &Data[TheEntry->TripleOffset]; }
+ StringRef getArch() const { return &Data[TheEntry->ArchOffset]; }
+ StringRef getFeatures() const { return &Data[TheEntry->FeaturesOffset]; }
+ StringRef getCmdLine() const { return &Data[TheEntry->CmdLineOffset]; }
+ StringRef getImage() const {
+ return StringRef(&Data[TheEntry->ImageOffset], TheEntry->ImageSize);
+ }
+
+ /// Convert the binary file to an offload file and write the image to the
+ /// associated \p Filename.
+ Expected<OffloadFile> createOffloadFile(StringRef Filename);
+
+private:
+ struct Header {
+ uint8_t Magic[4] = {0x10, 0xFF, 0x10, 0xAD};
+ uint32_t Version;
+ uint64_t Size;
+ uint64_t EntryOffset;
+ };
+
+ struct Entry {
+ uint16_t ImageKind;
+ uint16_t OffloadKind;
+ uint32_t Flags;
+ uint64_t TripleOffset;
+ uint64_t ArchOffset;
+ uint64_t FeaturesOffset;
+ uint64_t CmdLineOffset;
+ uint64_t ImageOffset;
+ uint64_t ImageSize;
+ };
+
+ OffloadBinary(MemoryBufferRef Buffer, const Header *TheHeader,
+ const Entry *TheEntry)
+ : Buffer(Buffer), Data(Buffer.getBufferStart()), TheHeader(TheHeader),
+ TheEntry(TheEntry) {}
+
+ OffloadBinary(const OffloadBinary &Other) = delete;
+
+ MemoryBufferRef Buffer;
+
+ /// Pointer to the beginning of the memory buffer.
+ const char *Data;
+ /// Location of the header within the binary.
+ const Header *TheHeader;
+ /// Location of the metadata entries within the binary.
+ const Entry *TheEntry;
+};
+
+ImageKind getImageKind(StringRef Name);
+StringRef getImageKindName(ImageKind Name);
+
+OffloadKind getOffloadKind(StringRef Name);
+StringRef getOffloadKindName(OffloadKind Name);
+
+} // namespace clang
+#endif
Index: clang/include/clang/Basic/CodeGenOptions.h
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.h
+++ clang/include/clang/Basic/CodeGenOptions.h
@@ -276,9 +276,9 @@
/// CUDA runtime back-end for incorporating them into host-side object file.
std::string CudaGpuBinaryFileName;
- /// List of filenames and section name pairs 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>,<section>'
+ /// 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 'file=<filename>,<key>=<metadata>, ...'
std::vector<std::string> OffloadObjects;
/// The name of the file to which the backend should save YAML optimization
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits