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