Index: include/llvm/Object/Binary.h =================================================================== --- include/llvm/Object/Binary.h +++ include/llvm/Object/Binary.h @@ -42,6 +42,7 @@ ID_Archive, ID_MachOUniversalBinary, ID_IR, // LLVM IR + ID_THINLTO, // ThinLTO info // Object and children. ID_StartObjects, @@ -117,6 +118,10 @@ return TypeID == ID_IR; } + bool isThinLTO() const { + return TypeID == ID_THINLTO; + } + bool isLittleEndian() const { return !(TypeID == ID_ELF32B || TypeID == ID_ELF64B || TypeID == ID_MachO32B || TypeID == ID_MachO64B); Index: include/llvm/Object/Error.h =================================================================== --- include/llvm/Object/Error.h +++ include/llvm/Object/Error.h @@ -33,6 +33,7 @@ macho_small_load_command, macho_load_segment_too_many_sections, macho_load_segment_too_small, + thinlto_section_not_found, }; inline std::error_code make_error_code(object_error e) { Index: include/llvm/Object/ThinLTOObjectFile.h =================================================================== --- /dev/null +++ include/llvm/Object/ThinLTOObjectFile.h @@ -0,0 +1,102 @@ +//===- ThinLTOObjectFile.h - ThinLTO object file implementation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the ThinLTOObjectFile template class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_THINLTOOBJECTFILE_H +#define LLVM_OBJECT_THINLTOOBJECTFILE_H + +#include "llvm/Object/SymbolicFile.h" + +namespace llvm { +class ThinLTOFunctionSummaryIndex; + +namespace object { +class ObjectFile; + +class ThinLTOObjectFile : public SymbolicFile { + std::unique_ptr Index; + +public: + ThinLTOObjectFile(MemoryBufferRef Object, + std::unique_ptr I); + ~ThinLTOObjectFile() override; + + // TODO: Walk through ThinLTOFunctionMap entries for function symbols. + void moveSymbolNext(DataRefImpl &Symb) const override { } + std::error_code printSymbolName(raw_ostream &OS, DataRefImpl Symb) const override { + return std::error_code(); + } + uint32_t getSymbolFlags(DataRefImpl Symb) const override { return 0; } + basic_symbol_iterator symbol_begin_impl() const override { } + basic_symbol_iterator symbol_end_impl() const override { } + + const ThinLTOFunctionSummaryIndex &getIndex() const { + return const_cast(this)->getIndex(); + } + ThinLTOFunctionSummaryIndex &getIndex() { + return *Index; + } + std::unique_ptr takeIndex(); + + static inline bool classof(const Binary *v) { + return v->isThinLTO(); + } + + /// \brief Write the index saved here to the given file. If we want + /// to write in native object wrapped format the target triple is + /// passed, otherwise write as normal bitcode. + std::error_code writeToFile(const char* path, const char* triple); + + /// \brief Looks for ThinLTO information in the given memory buffer + /// (which may be either a bitcode file or a native object file + /// with embedded bitcode), returns true if found, else false. + static bool hasThinLTOInMemBuffer(MemoryBufferRef Object, + LLVMContext &Context); + + /// \brief Parse ThinLTO information in the given memory buffer + /// (which may be either a bitcode file or a native object file + /// with embedded bitcode). Return new ThinLTOObjectFile instance + /// containing parsed ThinLTO summary/index. + static ErrorOr> + create(MemoryBufferRef Object, LLVMContext &Context, + bool ReadFuncSummaryData = true); + + /// \brief Parse the ThinLTO summary information for function with the + /// given name out of the given buffer (which may be either a bitcode file + /// or a native object file with embedded bitcode). Parsed information is + /// stored on the index object saved in this object. + std::error_code findThinLTOFunctionInfoInMemBuffer( + MemoryBufferRef Object, LLVMContext &Context, StringRef FunctionName); + +private: + /// \brief Finds and returns ThinLTO summary section embedded in the given + /// object file, or an error code if not found. + static ErrorOr findThinLTOSummaryInObject( + const ObjectFile &Obj); + + /// \brief Finds and returns ThinLTO module path string section embedded + /// in the given object file, or an error code if not found. + static ErrorOr findThinLTOModStringsInObject( + const ObjectFile &Obj); + + /// \brief Looks for ThinLTO summary section embedded in the given + /// object file, returns true if found, else false. + static bool hasThinLTOSummaryInObject(const ObjectFile &Obj); + + /// \brief Looks for ThinLTO summary section embedded in the given + /// object file, returns true if found, else false. + static bool hasThinLTOModStringsInObject(const ObjectFile &Obj); +}; +} +} + +#endif Index: lib/Object/CMakeLists.txt =================================================================== --- lib/Object/CMakeLists.txt +++ lib/Object/CMakeLists.txt @@ -16,6 +16,7 @@ RecordStreamer.cpp SymbolicFile.cpp SymbolSize.cpp + ThinLTOObjectFile.cpp ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/Object Index: lib/Object/ThinLTOObjectFile.cpp =================================================================== --- /dev/null +++ lib/Object/ThinLTOObjectFile.cpp @@ -0,0 +1,260 @@ +//===- ThinLTOObjectFile.cpp - ThinLTO object file implementation ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Part of the ThinLTOObjectFile class implementation. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/ThinLTOObjectFile.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/ThinLTOInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; +using namespace object; + +ThinLTOObjectFile::ThinLTOObjectFile( + MemoryBufferRef Object, std::unique_ptr I) + : SymbolicFile(Binary::ID_THINLTO, Object), Index(std::move(I)) { +} + +ThinLTOObjectFile::~ThinLTOObjectFile() { +} + +// Write the index saved here to the given file. If we want +// to write in native object wrapped format the target triple is +// passed, otherwise write as normal bitcode. +std::error_code ThinLTOObjectFile::writeToFile(const char* path, + const char* triple) { + std::error_code EC; + raw_fd_ostream OS(path, EC, sys::fs::OpenFlags::F_None); + if (triple) { + // TODO: create real MCStreamer object from OS and triple. + MCStreamer *MS = nullptr; + WriteThinLTOToStreamer(Index.get(), *MS); + } else { + WriteThinLTOToFile(Index.get(), OS); + } + return EC; +} + +std::unique_ptr ThinLTOObjectFile::takeIndex() { + return std::move(Index); +} + +// Look for a ThinLTO summary section in the given native object file. +bool ThinLTOObjectFile::hasThinLTOSummaryInObject(const ObjectFile &Obj) { + for (const SectionRef &Sec : Obj.sections()) { + StringRef SecName; + if (std::error_code EC = Sec.getName(SecName)) + return false; + if (SecName == ".llvm_thinlto_funcsum") { + StringRef SecContents; + if (std::error_code EC = Sec.getContents(SecContents)) + return false; + return true; + } + } + return false; +} + +// Look for a ThinLTO module strings section in the given native object file. +bool ThinLTOObjectFile::hasThinLTOModStringsInObject(const ObjectFile &Obj) { + for (const SectionRef &Sec : Obj.sections()) { + StringRef SecName; + if (std::error_code EC = Sec.getName(SecName)) + return false; + if (SecName == ".llvm_thinlto_modstrtab") { + StringRef SecContents; + if (std::error_code EC = Sec.getContents(SecContents)) + return false; + return true; + } + } + return false; +} + +// Looks for ThinLTO information in the given memory buffer +// (which may be either a bitcode file or a native object file +// with embedded bitcode), returns true if found, else false. +bool ThinLTOObjectFile::hasThinLTOInMemBuffer(MemoryBufferRef Object, LLVMContext &Context) { + sys::fs::file_magic Type = sys::fs::identify_magic(Object.getBuffer()); + switch (Type) { + case sys::fs::file_magic::bitcode: { + return hasThinLTOIndex(Object, Context, nullptr); + } + case sys::fs::file_magic::elf_relocatable: + case sys::fs::file_magic::macho_object: + case sys::fs::file_magic::coff_object: { + ErrorOr> ObjFile = + ObjectFile::createObjectFile(Object, Type); + assert(ObjFile); + bool HasSummary = + ThinLTOObjectFile::hasThinLTOSummaryInObject(*ObjFile->get()); + bool HasModStrings = + ThinLTOObjectFile::hasThinLTOModStringsInObject(*ObjFile->get()); + assert(HasSummary == HasModStrings); + return HasSummary && HasModStrings; + } + default: + assert(false); + } + return false; +} + +// Finds and returns ThinLTO summary section embedded in the given +// object file, or an error code if not found. +ErrorOr ThinLTOObjectFile::findThinLTOSummaryInObject( + const ObjectFile &Obj) { + for (const SectionRef &Sec : Obj.sections()) { + StringRef SecName; + if (std::error_code EC = Sec.getName(SecName)) + return EC; + if (SecName == ".llvm_thinlto_funcsum") { + StringRef SecContents; + if (std::error_code EC = Sec.getContents(SecContents)) + return EC; + return SecContents; + } + } + + return object_error::thinlto_section_not_found; +} + +// Finds and returns ThinLTO module path string section embedded +// in the given object file, or an error code if not found. +ErrorOr ThinLTOObjectFile::findThinLTOModStringsInObject( + const ObjectFile &Obj) { + for (const SectionRef &Sec : Obj.sections()) { + StringRef SecName; + if (std::error_code EC = Sec.getName(SecName)) + return EC; + if (SecName == ".llvm_thinlto_modstrtab") { + StringRef SecContents; + if (std::error_code EC = Sec.getContents(SecContents)) + return EC; + return SecContents; + } + } + + return object_error::thinlto_section_not_found; +} + +// TODO: +// Create/return unique_ptr to ThinLTOFunctionMap, parsing symtab +// in Obj. Should be an ObjectFile method instead, or invoke one? +static std::unique_ptr +createThinLTOFunctionMap(const ObjectFile &Obj) { + return llvm::make_unique(); +} + +// Parse ThinLTO information in the given memory buffer +// (which may be either a bitcode file or a native object file +// with embedded bitcode). Return new ThinLTOObjectFile instance +// containing parsed ThinLTO summary/index. +ErrorOr> +llvm::object::ThinLTOObjectFile::create(MemoryBufferRef Object, + LLVMContext &Context, + bool ReadFuncSummaryData) { + std::unique_ptr Index; + sys::fs::file_magic Type = sys::fs::identify_magic(Object.getBuffer()); + switch (Type) { + case sys::fs::file_magic::bitcode: { + ErrorOr> IOrErr = + getThinLTOIndex(Object, Context, nullptr, ReadFuncSummaryData); + if (std::error_code EC = IOrErr.getError()) + return EC; + + Index = std::move(IOrErr.get()); + + break; + } + case sys::fs::file_magic::elf_relocatable: + case sys::fs::file_magic::macho_object: + case sys::fs::file_magic::coff_object: { + ErrorOr> ObjFile = + ObjectFile::createObjectFile(Object, Type); + if (!ObjFile) + return ObjFile.getError(); + const ObjectFile &Obj = *ObjFile->get(); + + // static createThinLTOFunctionMap(const ObjectFile &Obj) + // Create/return unique_ptr to ThinLTOFunctionMap, parsing symtab + // in Obj. Should be an ObjectFile method instead, or invoke one? + std::unique_ptr FuncMap = + std::move(createThinLTOFunctionMap(Obj)); + + MemoryBufferRef SummaryBuff; + if (ReadFuncSummaryData) { + ErrorOr SROrErr = findThinLTOSummaryInObject(Obj); + if (!SROrErr) + return SROrErr.getError(); + SummaryBuff = MemoryBufferRef(SROrErr.get(), Obj.getFileName()); + } + + ErrorOr SROrErr = findThinLTOModStringsInObject(Obj); + if (!SROrErr) + return SROrErr.getError(); + MemoryBufferRef ModStringsBuff = + MemoryBufferRef(SROrErr.get(), Obj.getFileName()); + + ErrorOr> IOrErr = + getThinLTOIndex(SummaryBuff, ModStringsBuff, std::move(FuncMap), + Context, nullptr); + if (std::error_code EC = IOrErr.getError()) + return EC; + + Index = std::move(IOrErr.get()); + + break; + } + default: + return object_error::invalid_file_type; + } + + return llvm::make_unique(Object, std::move(Index)); +} + +// Parse the ThinLTO summary information for function with the +// given name out of the given buffer (which may be either a bitcode file +// or a native object file with embedded bitcode). Parsed information is +// stored on the index object saved in this object. +std::error_code ThinLTOObjectFile::findThinLTOFunctionInfoInMemBuffer( + MemoryBufferRef Object, LLVMContext &Context, StringRef FunctionName) { + sys::fs::file_magic Type = sys::fs::identify_magic(Object.getBuffer()); + switch (Type) { + case sys::fs::file_magic::bitcode: { + return readThinLTOFunctionInfo(Object, Context, nullptr, + FunctionName, std::move(Index)); + } + case sys::fs::file_magic::elf_relocatable: + case sys::fs::file_magic::macho_object: + case sys::fs::file_magic::coff_object: { + ErrorOr> ObjFile = + ObjectFile::createObjectFile(Object, Type); + if (!ObjFile) + return ObjFile.getError(); + const ObjectFile &Obj = *ObjFile->get(); + + ErrorOr SROrErr = findThinLTOSummaryInObject(Obj); + if (!SROrErr) + return SROrErr.getError(); + MemoryBufferRef SummaryBuff = MemoryBufferRef(SROrErr.get(), + Obj.getFileName()); + + return readThinLTOFunctionInfo(SummaryBuff, Context, nullptr, + FunctionName, std::move(Index)); + } + default: + return object_error::invalid_file_type; + } +}