From ed801ad5e5fef76c4303d04fd8de21662b428bee Mon Sep 17 00:00:00 2001 From: Joseph Huber Date: Fri, 1 Jul 2022 22:40:41 -0400 Subject: [PATCH] [Clang] Use metadata to make identifying embedded objects easier Currently we use the `embedBufferInModule` function to store binary strings containing device offloading data inside the host object to create a fatbinary. In the case of LTO, we need to extract this object from the LLVM-IR. This patch adds a metadata node for the embedded objects containing the embedded pointers and the sections they were stored at. This should create a cleaner interface for identifying these values. In the future it may be worthwhile to also encode an `ID` in the metadata corresponding to the object's special section type if relevant. This would allow us to extract the data from an object file and LLVM-IR using the same ID. Reviewed By: jdoerfert Differential Revision: https://reviews.llvm.org/D129033 --- clang/test/Frontend/embed-object.c | 3 +++ clang/test/Frontend/embed-object.ll | 4 ++++ .../clang-linker-wrapper/ClangLinkerWrapper.cpp | 22 ++++++++++++++++++---- llvm/docs/LangRef.rst | 13 +++++++++++++ llvm/include/llvm/Transforms/Utils/ModuleUtils.h | 3 ++- llvm/lib/Transforms/Utils/ModuleUtils.cpp | 7 +++++++ 6 files changed, 47 insertions(+), 5 deletions(-) diff --git a/clang/test/Frontend/embed-object.c b/clang/test/Frontend/embed-object.c index ceb3378..364cb8a 100644 --- a/clang/test/Frontend/embed-object.c +++ b/clang/test/Frontend/embed-object.c @@ -4,3 +4,6 @@ // CHECK: @llvm.compiler.used = appending global [1 x ptr] [ptr @[[OBJECT]]], section "llvm.metadata" void foo(void) {} + +// CHECK: !llvm.embedded.objects = !{![[METADATA:[0-9]+]]} +// CHECK: ![[METADATA]] = !{ptr @[[OBJECT]], !".llvm.offloading"} diff --git a/clang/test/Frontend/embed-object.ll b/clang/test/Frontend/embed-object.ll index 177ecdf..bcb56fd 100644 --- a/clang/test/Frontend/embed-object.ll +++ b/clang/test/Frontend/embed-object.ll @@ -13,3 +13,7 @@ define i32 @foo() { ret i32 0 } + +; CHECK: !llvm.embedded.objects = !{![[METADATA_1:[0-9]+]], ![[METADATA_2:[0-9]+]]} +; CHECK: ![[METADATA_1]] = !{ptr @[[OBJECT_1]], !".llvm.offloading"} +; CHECK: ![[METADATA_2]] = !{ptr @[[OBJECT_2]], !".llvm.offloading"} diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp index 3e935bc..e7214eb 100644 --- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp +++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp @@ -366,12 +366,26 @@ Error extractFromBitcode(std::unique_ptr Buffer, return createStringError(inconvertibleErrorCode(), "Failed to create module"); - // Extract offloading data from globals with the `.llvm.offloading` section. - for (GlobalVariable &GV : M->globals()) { - if (!GV.hasSection() || !GV.getSection().equals(OFFLOAD_SECTION_MAGIC_STR)) + // Extract offloading data from globals referenced by the + // `llvm.embedded.object` metadata with the `.llvm.offloading` section. + auto MD = M->getNamedMetadata("llvm.embedded.object"); + if (!MD) + return Error::success(); + + for (const MDNode *Op : MD->operands()) { + if (Op->getNumOperands() < 2) + continue; + + MDString *SectionID = dyn_cast(Op->getOperand(1)); + if (!SectionID || SectionID->getString() != OFFLOAD_SECTION_MAGIC_STR) + continue; + + GlobalVariable *GV = + mdconst::dyn_extract_or_null(Op->getOperand(0)); + if (!GV) continue; - auto *CDS = dyn_cast(GV.getInitializer()); + auto *CDS = dyn_cast(GV->getInitializer()); if (!CDS) continue; diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 889eca2..e74aaa8 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -7429,6 +7429,19 @@ Some optimisations are only when the entire LTO unit is present in the current module. This is represented by the ``LTOPostLink`` module flags metadata, which will be created with a value of ``1`` when LTO linking occurs. +Embedded Objects Names Metadata +=============================== + +Offloading compilations need to embed device code into the host section table to +create a fat binary. This metadata node references each global that will be +embedded in the module. The primary use for this is to make referencing these +globals more efficient in the IR. The metadata references nodes containing +pointers to the global to be embedded followed by the section name it will be +stored at:: + + !llvm.embedded.objects = !{!0} + !0 = !{ptr @object, !".section"} + Automatic Linker Flags Named Metadata ===================================== diff --git a/llvm/include/llvm/Transforms/Utils/ModuleUtils.h b/llvm/include/llvm/Transforms/Utils/ModuleUtils.h index 85263fc..335cf7a 100644 --- a/llvm/include/llvm/Transforms/Utils/ModuleUtils.h +++ b/llvm/include/llvm/Transforms/Utils/ModuleUtils.h @@ -109,7 +109,8 @@ void filterDeadComdatFunctions( std::string getUniqueModuleId(Module *M); /// Embed the memory buffer \p Buf into the module \p M as a global using the -/// specified section name. +/// specified section name. Also provide a metadata entry to identify it in the +/// module using the same section name. void embedBufferInModule(Module &M, MemoryBufferRef Buf, StringRef SectionName, Align Alignment = Align(1)); diff --git a/llvm/lib/Transforms/Utils/ModuleUtils.cpp b/llvm/lib/Transforms/Utils/ModuleUtils.cpp index 5120ade..a3529bf 100644 --- a/llvm/lib/Transforms/Utils/ModuleUtils.cpp +++ b/llvm/lib/Transforms/Utils/ModuleUtils.cpp @@ -275,5 +275,12 @@ void llvm::embedBufferInModule(Module &M, MemoryBufferRef Buf, GV->setSection(SectionName); GV->setAlignment(Alignment); + LLVMContext &Ctx = M.getContext(); + NamedMDNode *MD = M.getOrInsertNamedMetadata("llvm.embedded.objects"); + Metadata *MDVals[] = {ConstantAsMetadata::get(GV), + MDString::get(Ctx, SectionName)}; + + MD->addOperand(llvm::MDNode::get(Ctx, MDVals)); + appendToCompilerUsed(M, GV); } -- 2.7.4