Path: blob/main/contrib/llvm-project/llvm/lib/CGData/CodeGenDataReader.cpp
213764 views
//===- CodeGenDataReader.cpp ----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains support for reading codegen data.9//10//===----------------------------------------------------------------------===//1112#include "llvm/CGData/CodeGenDataReader.h"13#include "llvm/CGData/OutlinedHashTreeRecord.h"14#include "llvm/Object/ObjectFile.h"15#include "llvm/Support/CommandLine.h"16#include "llvm/Support/MemoryBuffer.h"1718#define DEBUG_TYPE "cg-data-reader"1920using namespace llvm;2122static cl::opt<bool> IndexedCodeGenDataReadFunctionMapNames(23"indexed-codegen-data-read-function-map-names", cl::init(true), cl::Hidden,24cl::desc("Read function map names in indexed CodeGenData. Can be "25"disabled to save memory and time for final consumption of the "26"indexed CodeGenData in production."));2728namespace llvm {2930static Expected<std::unique_ptr<MemoryBuffer>>31setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS) {32auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN()33: FS.getBufferForFile(Filename);34if (std::error_code EC = BufferOrErr.getError())35return errorCodeToError(EC);36return std::move(BufferOrErr.get());37}3839Error CodeGenDataReader::mergeFromObjectFile(40const object::ObjectFile *Obj, OutlinedHashTreeRecord &GlobalOutlineRecord,41StableFunctionMapRecord &GlobalFunctionMapRecord,42stable_hash *CombinedHash) {43Triple TT = Obj->makeTriple();44auto CGOutlineName =45getCodeGenDataSectionName(CG_outline, TT.getObjectFormat(), false);46auto CGMergeName =47getCodeGenDataSectionName(CG_merge, TT.getObjectFormat(), false);4849auto processSectionContents = [&](const StringRef &Name,50const StringRef &Contents) {51if (Name != CGOutlineName && Name != CGMergeName)52return;53if (CombinedHash)54*CombinedHash = stable_hash_combine(*CombinedHash, xxh3_64bits(Contents));55auto *Data = reinterpret_cast<const unsigned char *>(Contents.data());56auto *EndData = Data + Contents.size();57// In case dealing with an executable that has concatenated cgdata,58// we want to merge them into a single cgdata.59// Although it's not a typical workflow, we support this scenario60// by looping over all data in the sections.61if (Name == CGOutlineName) {62while (Data != EndData) {63OutlinedHashTreeRecord LocalOutlineRecord;64LocalOutlineRecord.deserialize(Data);65GlobalOutlineRecord.merge(LocalOutlineRecord);66}67} else if (Name == CGMergeName) {68while (Data != EndData) {69StableFunctionMapRecord LocalFunctionMapRecord;70LocalFunctionMapRecord.deserialize(Data);71GlobalFunctionMapRecord.merge(LocalFunctionMapRecord);72}73}74};7576for (auto &Section : Obj->sections()) {77Expected<StringRef> NameOrErr = Section.getName();78if (!NameOrErr)79return NameOrErr.takeError();80Expected<StringRef> ContentsOrErr = Section.getContents();81if (!ContentsOrErr)82return ContentsOrErr.takeError();83processSectionContents(*NameOrErr, *ContentsOrErr);84}8586return Error::success();87}8889Error IndexedCodeGenDataReader::read() {90using namespace support;9192// The smallest header with the version 1 is 24 bytes.93// Do not update this value even with the new version of the header.94const unsigned MinHeaderSize = 24;95if (DataBuffer->getBufferSize() < MinHeaderSize)96return error(cgdata_error::bad_header);9798auto *Start =99reinterpret_cast<const unsigned char *>(DataBuffer->getBufferStart());100auto *End =101reinterpret_cast<const unsigned char *>(DataBuffer->getBufferEnd());102if (auto E = IndexedCGData::Header::readFromBuffer(Start).moveInto(Header))103return E;104105if (hasOutlinedHashTree()) {106const unsigned char *Ptr = Start + Header.OutlinedHashTreeOffset;107if (Ptr >= End)108return error(cgdata_error::eof);109HashTreeRecord.deserialize(Ptr);110}111if (hasStableFunctionMap()) {112const unsigned char *Ptr = Start + Header.StableFunctionMapOffset;113if (Ptr >= End)114return error(cgdata_error::eof);115FunctionMapRecord.deserialize(Ptr, IndexedCodeGenDataReadFunctionMapNames);116}117118return success();119}120121Expected<std::unique_ptr<CodeGenDataReader>>122CodeGenDataReader::create(const Twine &Path, vfs::FileSystem &FS) {123// Set up the buffer to read.124auto BufferOrError = setupMemoryBuffer(Path, FS);125if (Error E = BufferOrError.takeError())126return std::move(E);127return CodeGenDataReader::create(std::move(BufferOrError.get()));128}129130Expected<std::unique_ptr<CodeGenDataReader>>131CodeGenDataReader::create(std::unique_ptr<MemoryBuffer> Buffer) {132if (Buffer->getBufferSize() == 0)133return make_error<CGDataError>(cgdata_error::empty_cgdata);134135std::unique_ptr<CodeGenDataReader> Reader;136// Create the reader.137if (IndexedCodeGenDataReader::hasFormat(*Buffer))138Reader = std::make_unique<IndexedCodeGenDataReader>(std::move(Buffer));139else if (TextCodeGenDataReader::hasFormat(*Buffer))140Reader = std::make_unique<TextCodeGenDataReader>(std::move(Buffer));141else142return make_error<CGDataError>(cgdata_error::malformed);143144// Initialize the reader and return the result.145if (Error E = Reader->read())146return std::move(E);147148return std::move(Reader);149}150151bool IndexedCodeGenDataReader::hasFormat(const MemoryBuffer &DataBuffer) {152using namespace support;153if (DataBuffer.getBufferSize() < sizeof(IndexedCGData::Magic))154return false;155156uint64_t Magic = endian::read<uint64_t, llvm::endianness::little, aligned>(157DataBuffer.getBufferStart());158// Verify that it's magical.159return Magic == IndexedCGData::Magic;160}161162bool TextCodeGenDataReader::hasFormat(const MemoryBuffer &Buffer) {163// Verify that this really looks like plain ASCII text by checking a164// 'reasonable' number of characters (up to the magic size).165StringRef Prefix = Buffer.getBuffer().take_front(sizeof(uint64_t));166return llvm::all_of(Prefix, [](char c) { return isPrint(c) || isSpace(c); });167}168Error TextCodeGenDataReader::read() {169using namespace support;170171// Parse the custom header line by line.172for (; !Line.is_at_eof(); ++Line) {173// Skip empty or whitespace-only lines174if (Line->trim().empty())175continue;176177if (!Line->starts_with(":"))178break;179StringRef Str = Line->drop_front().rtrim();180if (Str.equals_insensitive("outlined_hash_tree"))181DataKind |= CGDataKind::FunctionOutlinedHashTree;182else if (Str.equals_insensitive("stable_function_map"))183DataKind |= CGDataKind::StableFunctionMergingMap;184else185return error(cgdata_error::bad_header);186}187188// We treat an empty header (that is a comment # only) as a valid header.189if (Line.is_at_eof()) {190if (DataKind == CGDataKind::Unknown)191return Error::success();192return error(cgdata_error::bad_header);193}194195// The YAML docs follow after the header.196const char *Pos = Line->data();197size_t Size = reinterpret_cast<size_t>(DataBuffer->getBufferEnd()) -198reinterpret_cast<size_t>(Pos);199yaml::Input YOS(StringRef(Pos, Size));200if (hasOutlinedHashTree())201HashTreeRecord.deserializeYAML(YOS);202if (hasStableFunctionMap())203FunctionMapRecord.deserializeYAML(YOS);204205return Error::success();206}207} // end namespace llvm208209210