diff options
author | Francis Visoiu Mistrih <francisvm@yahoo.com> | 2019-09-10 15:48:55 -0700 |
---|---|---|
committer | Francis Visoiu Mistrih <francisvm@yahoo.com> | 2019-10-31 15:26:55 -0700 |
commit | e72e59e90287c50539cb2c0afbf197aa0101a023 (patch) | |
tree | 0c7481dcc08c20c59d650247175f8d0547790c0c /llvm/lib/Remarks/RemarkLinker.cpp | |
parent | f9061049c1542579f661c3ec25528439ab9d0588 (diff) | |
download | bcm5719-llvm-e72e59e90287c50539cb2c0afbf197aa0101a023.tar.gz bcm5719-llvm-e72e59e90287c50539cb2c0afbf197aa0101a023.zip |
[Remarks] Add support for linking remarks
Remarks are usually emitted per-TU, and for generating a standalone
remark file that can be shipped with the linked binary we need some kind
of tool to merge everything together.
The remarks::RemarkLinker class takes care of this and:
* Deduplicates remarks
* Filters remarks with no debug location
* Merges string tables from all the entries
As an output, it provides an iterator range that can be used to
serialize the remarks to a file.
Differential Revision: https://reviews.llvm.org/D69141
Diffstat (limited to 'llvm/lib/Remarks/RemarkLinker.cpp')
-rw-r--r-- | llvm/lib/Remarks/RemarkLinker.cpp | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/llvm/lib/Remarks/RemarkLinker.cpp b/llvm/lib/Remarks/RemarkLinker.cpp new file mode 100644 index 00000000000..617ce770af6 --- /dev/null +++ b/llvm/lib/Remarks/RemarkLinker.cpp @@ -0,0 +1,126 @@ +//===- RemarkLinker.cpp ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides an implementation of the remark linker. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Remarks/RemarkLinker.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Remarks/BitstreamRemarkContainer.h" +#include "llvm/Remarks/RemarkParser.h" +#include "llvm/Remarks/RemarkSerializer.h" +#include "llvm/Support/Error.h" + +using namespace llvm; +using namespace llvm::remarks; + +static Expected<StringRef> +getRemarksSectionName(const object::ObjectFile &Obj) { + if (Obj.isMachO()) + return StringRef("__remarks"); + // ELF -> .remarks, but there is no ELF support at this point. + return createStringError(std::errc::illegal_byte_sequence, + "Unsupported file format."); +} + +Expected<Optional<StringRef>> +llvm::remarks::getRemarksSectionContents(const object::ObjectFile &Obj) { + Expected<StringRef> SectionName = getRemarksSectionName(Obj); + if (!SectionName) + return SectionName.takeError(); + + for (const object::SectionRef &Section : Obj.sections()) { + Expected<StringRef> MaybeName = Section.getName(); + if (!MaybeName) + return MaybeName.takeError(); + if (*MaybeName != *SectionName) + continue; + + if (Expected<StringRef> Contents = Section.getContents()) + return *Contents; + else + return Contents.takeError(); + } + return Optional<StringRef>{}; +} + +Remark &RemarkLinker::keep(std::unique_ptr<Remark> Remark) { + StrTab.internalize(*Remark); + auto Inserted = Remarks.insert(std::move(Remark)); + return **Inserted.first; +} + +void RemarkLinker::setExternalFilePrependPath(StringRef PrependPathIn) { + PrependPath = PrependPathIn; +} + +// Discard remarks with no source location. +static bool shouldKeepRemark(const Remark &R) { return R.Loc.hasValue(); } + +Error RemarkLinker::link(StringRef Buffer, Optional<Format> RemarkFormat) { + if (!RemarkFormat) { + Expected<Format> ParserFormat = magicToFormat(Buffer); + if (!ParserFormat) + return ParserFormat.takeError(); + RemarkFormat = *ParserFormat; + } + + Expected<std::unique_ptr<RemarkParser>> MaybeParser = + createRemarkParserFromMeta( + *RemarkFormat, Buffer, /*StrTab=*/None, + PrependPath ? Optional<StringRef>(StringRef(*PrependPath)) + : Optional<StringRef>(None)); + if (!MaybeParser) + return MaybeParser.takeError(); + + RemarkParser &Parser = **MaybeParser; + + while (true) { + Expected<std::unique_ptr<Remark>> Next = Parser.next(); + if (Error E = Next.takeError()) { + if (E.isA<EndOfFileError>()) { + consumeError(std::move(E)); + break; + } + return E; + } + + assert(*Next != nullptr); + + if (shouldKeepRemark(**Next)) + keep(std::move(*Next)); + } + return Error::success(); +} + +Error RemarkLinker::link(const object::ObjectFile &Obj, + Optional<Format> RemarkFormat) { + Expected<Optional<StringRef>> SectionOrErr = getRemarksSectionContents(Obj); + if (!SectionOrErr) + return SectionOrErr.takeError(); + + if (Optional<StringRef> Section = *SectionOrErr) + return link(*Section, RemarkFormat); + return Error::success(); +} + +Error RemarkLinker::serialize(raw_ostream &OS, Format RemarksFormat) const { + Expected<std::unique_ptr<RemarkSerializer>> MaybeSerializer = + createRemarkSerializer(RemarksFormat, SerializerMode::Standalone, OS, + std::move(const_cast<StringTable &>(StrTab))); + if (!MaybeSerializer) + return MaybeSerializer.takeError(); + + std::unique_ptr<remarks::RemarkSerializer> Serializer = + std::move(*MaybeSerializer); + + for (const Remark &R : remarks()) + Serializer->emit(R); + return Error::success(); +} |