jhuber6 created this revision.
jhuber6 added reviewers: jdoerfert, gregrodgers, JonChesterfield, ronlieb.
Herald added subscribers: ormris, dexonsmith, dang, guansong, hiraditya, yaxunl.
jhuber6 requested review of this revision.
Herald added subscribers: llvm-commits, cfe-commits, sstefan1.
Herald added projects: clang, LLVM.

This patch adds support for a flag `-fembed-offload-binary` to embed a
file as an ELF section in the output by placing it in a global variable.
This can be used to bundle offloading files with the host binary so it
can be accessed by the linker. The section is named using the
`-fembed-offload-section` option.

Depends on D116541 <https://reviews.llvm.org/D116541>


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D116542

Files:
  clang/include/clang/Basic/CodeGenOptions.h
  clang/include/clang/CodeGen/BackendUtil.h
  clang/include/clang/Driver/Options.td
  clang/lib/CodeGen/BackendUtil.cpp
  clang/lib/CodeGen/CodeGenAction.cpp
  clang/test/Frontend/embed-object.ll
  llvm/include/llvm/Bitcode/BitcodeWriter.h
  llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
===================================================================
--- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -4971,3 +4971,42 @@
       llvm::ConstantArray::get(ATy, UsedArray), "llvm.compiler.used");
   NewUsed->setSection("llvm.metadata");
 }
+
+void llvm::EmbedObjectInModule(llvm::Module &M, llvm::MemoryBufferRef Buf,
+                               StringRef SectionName) {
+  // Save llvm.compiler.used and remove it.
+  SmallVector<Constant *, 2> UsedArray;
+  SmallVector<GlobalValue *, 4> UsedGlobals;
+  Type *UsedElementType = Type::getInt8Ty(M.getContext())->getPointerTo(0);
+  GlobalVariable *Used = collectUsedGlobalVariables(M, UsedGlobals, true);
+  for (auto *GV : UsedGlobals) {
+    if (!GV->getName().startswith("llvm.embedded.object"))
+      UsedArray.push_back(
+          ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, UsedElementType));
+  }
+  if (Used)
+    Used->eraseFromParent();
+
+  ArrayRef<uint8_t> ModuleData = ArrayRef<uint8_t>(
+      (const uint8_t *)Buf.getBufferStart(), Buf.getBufferSize());
+
+  // Embed the data in the 
+  llvm::Constant *ModuleConstant =
+      llvm::ConstantDataArray::get(M.getContext(), ModuleData);
+  llvm::GlobalVariable *GV = new llvm::GlobalVariable(
+      M, ModuleConstant->getType(), true, llvm::GlobalValue::PrivateLinkage,
+      ModuleConstant, "llvm.embedded.object");
+  GV->setSection(SectionName);
+  // Set alignment to 1 to prevent padding between two contributions from input
+  // sections after linking.
+  GV->setAlignment(Align(1));
+  UsedArray.push_back(
+      ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, UsedElementType));
+
+  // Recreate llvm.compiler.used.
+  ArrayType *ATy = ArrayType::get(UsedElementType, UsedArray.size());
+  auto *NewUsed = new GlobalVariable(
+      M, ATy, false, llvm::GlobalValue::AppendingLinkage,
+      llvm::ConstantArray::get(ATy, UsedArray), "llvm.compiler.used");
+  NewUsed->setSection("llvm.metadata");
+}
Index: llvm/include/llvm/Bitcode/BitcodeWriter.h
===================================================================
--- llvm/include/llvm/Bitcode/BitcodeWriter.h
+++ llvm/include/llvm/Bitcode/BitcodeWriter.h
@@ -165,6 +165,11 @@
                             bool EmbedCmdline,
                             const std::vector<uint8_t> &CmdArgs);
 
+  /// Embeds the memory buffer \p Buf into the module \p M as a global using the
+  /// section name \p SectionName.
+  void EmbedObjectInModule(Module &M, MemoryBufferRef Buf,
+                           StringRef SectionName);
+
 } // end namespace llvm
 
 #endif // LLVM_BITCODE_BITCODEWRITER_H
Index: clang/test/Frontend/embed-object.ll
===================================================================
--- /dev/null
+++ clang/test/Frontend/embed-object.ll
@@ -0,0 +1,13 @@
+; RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm \
+; RUN:    -fembed-offload-binary=%S/Inputs/empty.h -fembed-offload-section=section -x ir %s -o - \
+; RUN:    | FileCheck %s -check-prefix=CHECK
+
+; CHECK: @llvm.embedded.object = private constant [0 x i8] zeroinitializer, section ".llvm.offloading.section", align 1
+; CHECK: @llvm.compiler.used = appending global [2 x i8*] [i8* @x, i8* getelementptr inbounds ([0 x i8], [0 x i8]* @llvm.embedded.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"
+
+define i32 @foo() {
+  ret i32 0
+}
Index: clang/lib/CodeGen/CodeGenAction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenAction.cpp
+++ clang/lib/CodeGen/CodeGenAction.cpp
@@ -1134,6 +1134,7 @@
     TheModule->setTargetTriple(TargetOpts.Triple);
   }
 
+  EmbedBinary(TheModule.get(), CodeGenOpts, Diagnostics);
   EmbedBitcode(TheModule.get(), CodeGenOpts, *MainFile);
 
   LLVMContext &Ctx = TheModule->getContext();
Index: clang/lib/CodeGen/BackendUtil.cpp
===================================================================
--- clang/lib/CodeGen/BackendUtil.cpp
+++ clang/lib/CodeGen/BackendUtil.cpp
@@ -1738,8 +1738,43 @@
                          llvm::MemoryBufferRef Buf) {
   if (CGOpts.getEmbedBitcode() == CodeGenOptions::Embed_Off)
     return;
+
   llvm::EmbedBitcodeInModule(
       *M, Buf, CGOpts.getEmbedBitcode() != CodeGenOptions::Embed_Marker,
       CGOpts.getEmbedBitcode() != CodeGenOptions::Embed_Bitcode,
       CGOpts.CmdArgs);
 }
+
+void clang::EmbedBinary(llvm::Module *M, const CodeGenOptions &CGOpts,
+    DiagnosticsEngine &Diags) {
+  if (CGOpts.OffloadBinaryString.empty())
+    return;
+
+  SmallVector<StringRef, 4> BinaryFilenames;
+  SmallVector<StringRef, 4> BinarySections;
+  StringRef(CGOpts.OffloadBinaryString).split(BinaryFilenames, ",");
+  StringRef(CGOpts.OffloadSectionString).split(BinarySections, ",");
+
+  assert(BinaryFilenames.size() == BinarySections.size() &&
+         "Different number of filenames and section names in embedding");
+
+  auto BinarySection = BinarySections.begin();
+  for (StringRef BinaryFilename : BinaryFilenames) {
+    llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BinaryOrErr =
+      llvm::MemoryBuffer::getFileOrSTDIN(BinaryFilename);
+    if (std::error_code EC = BinaryOrErr.getError()) {
+      auto DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+          "could not open '%0' for embedding");
+      Diags.Report(DiagID) << BinaryFilename;
+      return;
+    }
+
+    SmallString<128> SectionName(".llvm.offloading");
+    if (!BinarySection->empty()) {
+      SectionName += ".";
+      SectionName += *BinarySection;
+    }
+    llvm::EmbedObjectInModule(*M, **BinaryOrErr, SectionName);
+    ++BinarySection;
+  }
+}
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -1148,6 +1148,14 @@
   PosFlag<SetTrue, [CC1Option], "Enable support for the C++ Coroutines TS">,
   NegFlag<SetFalse>>;
 
+def fembed_offload_binary_EQ : Joined<["-"], "fembed-offload-binary=">,
+  Group<f_Group>, Flags<[NoXarchOption, CC1Option]>,
+  HelpText<"Embed Offloading device-side binary into host object file.">,
+  MarshallingInfoString<CodeGenOpts<"OffloadBinaryString">>;
+def fembed_offload_section_EQ : Joined<["-"], "fembed-offload-section=">,
+  Group<f_Group>, Flags<[NoXarchOption, CC1Option]>,
+  HelpText<"Section name to use for the embedded device binary.">,
+  MarshallingInfoString<CodeGenOpts<"OffloadSectionString">>;
 def fembed_bitcode_EQ : Joined<["-"], "fembed-bitcode=">,
     Group<f_Group>, Flags<[NoXarchOption, CC1Option, CC1AsOption]>, MetaVarName<"<option>">,
     HelpText<"Embed LLVM bitcode (option: off, all, bitcode, marker)">,
Index: clang/include/clang/CodeGen/BackendUtil.h
===================================================================
--- clang/include/clang/CodeGen/BackendUtil.h
+++ clang/include/clang/CodeGen/BackendUtil.h
@@ -44,6 +44,9 @@
 
   void EmbedBitcode(llvm::Module *M, const CodeGenOptions &CGOpts,
                     llvm::MemoryBufferRef Buf);
+
+  void EmbedBinary(llvm::Module *M, const CodeGenOptions &CGOpts,
+                   DiagnosticsEngine &Diags);
 }
 
 #endif
Index: clang/include/clang/Basic/CodeGenOptions.h
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.h
+++ clang/include/clang/Basic/CodeGenOptions.h
@@ -276,6 +276,14 @@
   /// CUDA runtime back-end for incorporating them into host-side object file.
   std::string CudaGpuBinaryFileName;
 
+  /// List of file passed with -fembed-offload-binary option to embed
+  /// device-side offloading binaries in the host object file.
+  std::string OffloadBinaryString;
+
+  /// List of section names pass with -fembed-offload-binary to use when
+  /// embedding files passed with -fembed-offload-binary.
+  std::string OffloadSectionString;
+
   /// The name of the file to which the backend should save YAML optimization
   /// records.
   std::string OptRecordFile;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D116542: [OpenMP] Add... Joseph Huber via Phabricator via cfe-commits

Reply via email to