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/ThinLTOObjectFile.h =================================================================== --- /dev/null +++ include/llvm/Object/ThinLTOObjectFile.h @@ -0,0 +1,75 @@ +//===- 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 Looks for ThinLTO information in the given memory buffer, + /// returns true if found, else false. + static bool hasThinLTOInMemBuffer(MemoryBufferRef Object, + LLVMContext &Context); + + /// \brief Parse ThinLTO information in the given memory buffer. + /// 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. Parsed information is + /// stored on the index object saved in this object. + std::error_code findThinLTOFunctionInfoInMemBuffer( + MemoryBufferRef Object, LLVMContext &Context, StringRef FunctionName); +}; +} +} + +#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,92 @@ +//===- 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() { +} + +std::unique_ptr ThinLTOObjectFile::takeIndex() { + return std::move(Index); +} + +// Looks for ThinLTO information in the given memory buffer +// 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); + default: + assert(false); + } + return false; +} + +// Parse ThinLTO information in the given memory buffer. +// 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; + } + 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. 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 readThinLTOFunctionSummary(Object, Context, nullptr, + FunctionName, std::move(Index)); + } + default: + return object_error::invalid_file_type; + } +} Index: tools/gold/gold-plugin.cpp =================================================================== --- tools/gold/gold-plugin.cpp +++ tools/gold/gold-plugin.cpp @@ -31,6 +31,7 @@ #include "llvm/Linker/Linker.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Object/IRObjectFile.h" +#include "llvm/Object/ThinLTOObjectFile.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Host.h" #include "llvm/Support/ManagedStatic.h" @@ -79,6 +80,7 @@ static Reloc::Model RelocationModel = Reloc::Default; static std::string output_name = ""; static std::list Modules; +static bool IsThinLTO = false; static std::vector Cleanup; static llvm::TargetOptions TargetOpts; @@ -364,6 +366,15 @@ cf.handle = file->handle; + // If the file contains a ThinLTO index, then we are doing ThinLTO + // compilation. Don't need to process the symbols in this case, and + // we remember that this is ThinLTO so that we simply build a combined + // index file after all files are claimed. + if (hasThinLTOIndex(BufferRef, Context, nullptr)) { + IsThinLTO = true; + return LDPS_OK; + } + for (auto &Sym : Obj->symbols()) { uint32_t Symflags = Sym.getFlags(); if (shouldSkip(Symflags)) @@ -579,6 +590,31 @@ Sym.comdat_key = nullptr; } +static std::unique_ptr +getThinLTOIndexForFile(LLVMContext &Context, claimed_file &F, + ld_plugin_input_file &Info) { + + if (get_symbols(F.handle, F.syms.size(), &F.syms[0]) != LDPS_OK) + message(LDPL_FATAL, "Failed to get symbol information"); + + const void *View; + if (get_view(F.handle, &View) != LDPS_OK) + message(LDPL_FATAL, "Failed to get a view of file"); + + MemoryBufferRef BufferRef(StringRef((const char *)View, Info.filesize), + Info.name); + ErrorOr> ObjOrErr = + object::ThinLTOObjectFile::create(BufferRef, Context); + + if (std::error_code EC = ObjOrErr.getError()) + message(LDPL_FATAL, "Could not read ThinLTO bitcode from file : %s", + EC.message().c_str()); + + object::ThinLTOObjectFile &Obj = **ObjOrErr; + + return Obj.takeIndex(); +} + static std::unique_ptr getModuleForFile(LLVMContext &Context, claimed_file &F, ld_plugin_input_file &Info, raw_fd_ostream *ApiFile, @@ -835,6 +871,34 @@ LLVMContext Context; Context.setDiagnosticHandler(diagnosticHandler, nullptr, true); + // If we are doing ThinLTO compilation, simply build the combined + // function index/summary and emit it. We don't need to parse the modules + // and link them in this case. + if (IsThinLTO) { + std::unique_ptr CombinedIndex; + for (claimed_file &F : Modules) { + ld_plugin_input_file File; + if (get_input_file(F.handle, &File) != LDPS_OK) + message(LDPL_FATAL, "Failed to get file information"); + + std::unique_ptr Index = + getThinLTOIndexForFile(Context, F, File); + CombinedIndex->mergeFrom(Index.get()); + } + + std::error_code EC; + raw_fd_ostream OS(output_name + ".thinlto.bc", EC, + sys::fs::OpenFlags::F_None); + if (EC) + message(LDPL_FATAL, "Unable to open %s.thinlto.bc for writing: %s", + output_name.data(), EC.message().c_str()); + WriteThinLTOToFile(CombinedIndex.get(), OS); + OS.close(); + + cleanup_hook(); + exit(0); + } + std::unique_ptr Combined(new Module("ld-temp.o", Context)); Linker L(Combined.get());