diff options
| author | Francis Visoiu Mistrih <francisvm@yahoo.com> | 2019-05-30 21:45:59 +0000 |
|---|---|---|
| committer | Francis Visoiu Mistrih <francisvm@yahoo.com> | 2019-05-30 21:45:59 +0000 |
| commit | 6ada11f13466a758597f912156be47ffca2e1408 (patch) | |
| tree | 674f255cda23a10d29d2f08eba7622a101b28d5b /llvm | |
| parent | 31f1939848397e52617506e1a5af8035f4405a82 (diff) | |
| download | bcm5719-llvm-6ada11f13466a758597f912156be47ffca2e1408.tar.gz bcm5719-llvm-6ada11f13466a758597f912156be47ffca2e1408.zip | |
[Remarks][NFC] Move the serialization to lib/Remarks
Separate the remark serialization to YAML from the LLVM Diagnostics.
This adds a new serialization abstraction: remarks::Serializer. It's
completely independent from lib/IR and it provides an easy way to
replace YAML by providing a new remarks::Serializer.
Differential Revision: https://reviews.llvm.org/D62632
llvm-svn: 362160
Diffstat (limited to 'llvm')
| -rw-r--r-- | llvm/include/llvm/IR/DiagnosticInfo.h | 13 | ||||
| -rw-r--r-- | llvm/include/llvm/IR/RemarkStreamer.h | 34 | ||||
| -rw-r--r-- | llvm/include/llvm/Remarks/RemarkSerializer.h | 68 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 26 | ||||
| -rw-r--r-- | llvm/lib/IR/DiagnosticInfo.cpp | 137 | ||||
| -rw-r--r-- | llvm/lib/IR/RemarkStreamer.cpp | 78 | ||||
| -rw-r--r-- | llvm/lib/LTO/LTO.cpp | 5 | ||||
| -rw-r--r-- | llvm/lib/Remarks/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | llvm/lib/Remarks/YAMLRemarkSerializer.cpp | 166 | ||||
| -rw-r--r-- | llvm/tools/llc/llc.cpp | 5 | ||||
| -rw-r--r-- | llvm/tools/opt/opt.cpp | 3 |
11 files changed, 353 insertions, 183 deletions
diff --git a/llvm/include/llvm/IR/DiagnosticInfo.h b/llvm/include/llvm/IR/DiagnosticInfo.h index ab4c692e18b..373663289db 100644 --- a/llvm/include/llvm/IR/DiagnosticInfo.h +++ b/llvm/include/llvm/IR/DiagnosticInfo.h @@ -465,12 +465,15 @@ public: virtual bool isEnabled() const = 0; StringRef getPassName() const { return PassName; } + StringRef getRemarkName() const { return RemarkName; } std::string getMsg() const; Optional<uint64_t> getHotness() const { return Hotness; } void setHotness(Optional<uint64_t> H) { Hotness = H; } bool isVerbose() const { return IsVerbose; } + ArrayRef<Argument> getArgs() const { return Args; } + static bool classof(const DiagnosticInfo *DI) { return (DI->getKind() >= DK_FirstRemark && DI->getKind() <= DK_LastRemark) || @@ -500,7 +503,7 @@ protected: const char *PassName; /// Textual identifier for the remark (single-word, camel-case). Can be used - /// by external tools reading the YAML output file for optimization remarks to + /// by external tools reading the output file for optimization remarks to /// identify the remark. StringRef RemarkName; @@ -518,8 +521,6 @@ protected: /// the optimization records and not in the remark printed in the compiler /// output. int FirstExtraArgIndex = -1; - - friend struct yaml::MappingTraits<DiagnosticInfoOptimizationBase *>; }; /// Allow the insertion operator to return the actual remark type rather than a @@ -1001,12 +1002,6 @@ public: void print(DiagnosticPrinter &DP) const override; }; -namespace yaml { -template <> struct MappingTraits<DiagnosticInfoOptimizationBase *> { - static void mapping(IO &io, DiagnosticInfoOptimizationBase *&OptDiag); -}; -} // namespace yaml - } // end namespace llvm #endif // LLVM_IR_DIAGNOSTICINFO_H diff --git a/llvm/include/llvm/IR/RemarkStreamer.h b/llvm/include/llvm/IR/RemarkStreamer.h index b4672c269da..621ebb3436c 100644 --- a/llvm/include/llvm/IR/RemarkStreamer.h +++ b/llvm/include/llvm/IR/RemarkStreamer.h @@ -14,10 +14,9 @@ #define LLVM_IR_REMARKSTREAMER_H #include "llvm/IR/DiagnosticInfo.h" -#include "llvm/Remarks/RemarkStringTable.h" +#include "llvm/Remarks/RemarkSerializer.h" #include "llvm/Support/Error.h" #include "llvm/Support/Regex.h" -#include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" #include <string> #include <vector> @@ -27,33 +26,36 @@ namespace llvm { class RemarkStreamer { /// The filename that the remark diagnostics are emitted to. const std::string Filename; - /// The open raw_ostream that the remark diagnostics are emitted to. - raw_ostream &OS; /// The regex used to filter remarks based on the passes that emit them. Optional<Regex> PassFilter; + /// The object used to serialize the remarks to a specific format. + std::unique_ptr<remarks::Serializer> Serializer; - /// The YAML streamer. - yaml::Output YAMLOutput; - - /// The string table containing all the unique strings used in the output. - /// The table will be serialized in a section to be consumed after the - /// compilation. - remarks::StringTable StrTab; + /// Temporary buffer for converting diagnostics into remark objects. This is + /// used for the remark arguments that are converted from a vector of + /// diagnostic arguments to a vector of remark arguments. + SmallVector<remarks::Argument, 8> TmpArgs; + /// Convert diagnostics into remark objects. The result uses \p TmpArgs as a + /// temporary buffer for the remark arguments, and relies on all the strings + /// to be kept in memory until the next call to `toRemark`. + /// The lifetime of the members of the result is bound to the lifetime of both + /// the remark streamer and the LLVM diagnostics. + remarks::Remark toRemark(const DiagnosticInfoOptimizationBase &Diag); public: - RemarkStreamer(StringRef Filename, raw_ostream& OS); + RemarkStreamer(StringRef Filename, + std::unique_ptr<remarks::Serializer> Serializer); /// Return the filename that the remark diagnostics are emitted to. StringRef getFilename() const { return Filename; } /// Return stream that the remark diagnostics are emitted to. - raw_ostream &getStream() { return OS; } + raw_ostream &getStream() { return Serializer->OS; } + /// Return the serializer used for this stream. + remarks::Serializer &getSerializer() { return *Serializer; } /// Set a pass filter based on a regex \p Filter. /// Returns an error if the regex is invalid. Error setFilter(StringRef Filter); /// Emit a diagnostic through the streamer. void emit(const DiagnosticInfoOptimizationBase &Diag); - /// The string table used during emission. - remarks::StringTable &getStringTable() { return StrTab; } - const remarks::StringTable &getStringTable() const { return StrTab; } }; } // end namespace llvm diff --git a/llvm/include/llvm/Remarks/RemarkSerializer.h b/llvm/include/llvm/Remarks/RemarkSerializer.h new file mode 100644 index 00000000000..7431ace4d21 --- /dev/null +++ b/llvm/include/llvm/Remarks/RemarkSerializer.h @@ -0,0 +1,68 @@ +//===-- RemarkSerializer.h - Remark serialization interface -----*- C++ -*-===// +// +// 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 interface for serializing remarks to different formats. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_REMARKS_REMARK_SERIALIZER_H +#define LLVM_REMARKS_REMARK_SERIALIZER_H + +#include "llvm/Remarks/Remark.h" +#include "llvm/Remarks/RemarkStringTable.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +namespace remarks { + +/// This is the base class for a remark serializer. +/// It includes support for using a string table while emitting. +struct Serializer { + /// The open raw_ostream that the remark diagnostics are emitted to. + raw_ostream &OS; + /// The string table containing all the unique strings used in the output. + /// The table can be serialized to be consumed after the compilation. + Optional<StringTable> StrTab; + + Serializer(raw_ostream &OS) : OS(OS), StrTab() {} + + /// This is just an interface. + virtual ~Serializer() = default; + virtual void emit(const Remark &Remark) = 0; +}; + +/// Wether the serializer should use a string table while emitting. +enum class UseStringTable { No, Yes }; + +/// Serialize the remarks to YAML. One remark entry looks like this: +/// --- !<TYPE> +/// Pass: <PASSNAME> +/// Name: <REMARKNAME> +/// DebugLoc: { File: <SOURCEFILENAME>, Line: <SOURCELINE>, +/// Column: <SOURCECOLUMN> } +/// Function: <FUNCTIONNAME> +/// Args: +/// - <KEY>: <VALUE> +/// DebugLoc: { File: <FILE>, Line: <LINE>, Column: <COL> } +/// ... +struct YAMLSerializer : public Serializer { + /// The YAML streamer. + yaml::Output YAMLOutput; + + YAMLSerializer(raw_ostream &OS, + UseStringTable UseStringTable = UseStringTable::No); + + /// Emit a remark to the stream. + void emit(const Remark &Remark) override; +}; + +} // end namespace remarks +} // end namespace llvm + +#endif /* LLVM_REMARKS_REMARK_SERIALIZER_H */ diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 3317952d05d..7adc59d096f 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -100,6 +100,7 @@ #include "llvm/MC/SectionKind.h" #include "llvm/Pass.h" #include "llvm/Remarks/Remark.h" +#include "llvm/Remarks/RemarkStringTable.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" @@ -1347,6 +1348,7 @@ void AsmPrinter::emitRemarksSection(Module &M) { RemarkStreamer *RS = M.getContext().getRemarkStreamer(); if (!RS) return; + const remarks::Serializer &Serializer = RS->getSerializer(); // Switch to the right section: .remarks/__remarks. MCSection *RemarksSection = @@ -1368,23 +1370,27 @@ void AsmPrinter::emitRemarksSection(Module &M) { // Note: we need to use the streamer here to emit it in the section. We can't // just use the serialize function with a raw_ostream because of the way // MCStreamers work. - const remarks::StringTable &StrTab = RS->getStringTable(); - std::vector<StringRef> StrTabStrings = StrTab.serialize(); - uint64_t StrTabSize = StrTab.SerializedSize; + uint64_t StrTabSize = + Serializer.StrTab ? Serializer.StrTab->SerializedSize : 0; // Emit the total size of the string table (the size itself excluded): // little-endian uint64_t. // The total size is located after the version number. + // Note: even if no string table is used, emit 0. std::array<char, 8> StrTabSizeBuf; support::endian::write64le(StrTabSizeBuf.data(), StrTabSize); OutStreamer->EmitBinaryData( StringRef(StrTabSizeBuf.data(), StrTabSizeBuf.size())); - // Emit a list of null-terminated strings. - // Note: the order is important here: the ID used in the remarks corresponds - // to the position of the string in the section. - for (StringRef Str : StrTabStrings) { - OutStreamer->EmitBytes(Str); - // Explicitly emit a '\0'. - OutStreamer->EmitIntValue(/*Value=*/0, /*Size=*/1); + + if (const Optional<remarks::StringTable> &StrTab = Serializer.StrTab) { + std::vector<StringRef> StrTabStrings = StrTab->serialize(); + // Emit a list of null-terminated strings. + // Note: the order is important here: the ID used in the remarks corresponds + // to the position of the string in the section. + for (StringRef Str : StrTabStrings) { + OutStreamer->EmitBytes(Str); + // Explicitly emit a '\0'. + OutStreamer->EmitIntValue(/*Value=*/0, /*Size=*/1); + } } // Emit the null-terminated absolute path to the remark file. diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp index 7c387e95724..4a8e3cca349 100644 --- a/llvm/lib/IR/DiagnosticInfo.cpp +++ b/llvm/lib/IR/DiagnosticInfo.cpp @@ -43,8 +43,6 @@ using namespace llvm; -cl::opt<bool> UseStringTable("remarks-yaml-string-table", cl::init(false)); - int llvm::getNextAvailablePluginDiagnosticKind() { static std::atomic<int> PluginKindID(DK_FirstPluginKind); return ++PluginKindID; @@ -374,138 +372,3 @@ std::string DiagnosticInfoOptimizationBase::getMsg() const { void OptimizationRemarkAnalysisFPCommute::anchor() {} void OptimizationRemarkAnalysisAliasing::anchor() {} - -template <typename T> -static void mapRemarkHeader( - yaml::IO &io, T PassName, T RemarkName, DiagnosticLocation DL, - T FunctionName, Optional<uint64_t> Hotness, - SmallVectorImpl<DiagnosticInfoOptimizationBase::Argument> &Args) { - io.mapRequired("Pass", PassName); - io.mapRequired("Name", RemarkName); - if (!io.outputting() || DL.isValid()) - io.mapOptional("DebugLoc", DL); - io.mapRequired("Function", FunctionName); - io.mapOptional("Hotness", Hotness); - io.mapOptional("Args", Args); -} - -namespace llvm { -namespace yaml { - -void MappingTraits<DiagnosticInfoOptimizationBase *>::mapping( - IO &io, DiagnosticInfoOptimizationBase *&OptDiag) { - assert(io.outputting() && "input not yet implemented"); - - if (io.mapTag("!Passed", - (OptDiag->getKind() == DK_OptimizationRemark || - OptDiag->getKind() == DK_MachineOptimizationRemark))) - ; - else if (io.mapTag( - "!Missed", - (OptDiag->getKind() == DK_OptimizationRemarkMissed || - OptDiag->getKind() == DK_MachineOptimizationRemarkMissed))) - ; - else if (io.mapTag( - "!Analysis", - (OptDiag->getKind() == DK_OptimizationRemarkAnalysis || - OptDiag->getKind() == DK_MachineOptimizationRemarkAnalysis))) - ; - else if (io.mapTag("!AnalysisFPCommute", - OptDiag->getKind() == - DK_OptimizationRemarkAnalysisFPCommute)) - ; - else if (io.mapTag("!AnalysisAliasing", - OptDiag->getKind() == - DK_OptimizationRemarkAnalysisAliasing)) - ; - else if (io.mapTag("!Failure", OptDiag->getKind() == DK_OptimizationFailure)) - ; - else - llvm_unreachable("Unknown remark type"); - - // These are read-only for now. - DiagnosticLocation DL = OptDiag->getLocation(); - StringRef FN = - GlobalValue::dropLLVMManglingEscape(OptDiag->getFunction().getName()); - - StringRef PassName(OptDiag->PassName); - if (UseStringTable) { - remarks::StringTable &StrTab = - reinterpret_cast<RemarkStreamer *>(io.getContext())->getStringTable(); - unsigned PassID = StrTab.add(PassName).first; - unsigned NameID = StrTab.add(OptDiag->RemarkName).first; - unsigned FunctionID = StrTab.add(FN).first; - mapRemarkHeader(io, PassID, NameID, DL, FunctionID, OptDiag->Hotness, - OptDiag->Args); - } else { - mapRemarkHeader(io, PassName, OptDiag->RemarkName, DL, FN, OptDiag->Hotness, - OptDiag->Args); - } -} - -template <> struct MappingTraits<DiagnosticLocation> { - static void mapping(IO &io, DiagnosticLocation &DL) { - assert(io.outputting() && "input not yet implemented"); - - StringRef File = DL.getRelativePath(); - unsigned Line = DL.getLine(); - unsigned Col = DL.getColumn(); - - if (UseStringTable) { - remarks::StringTable &StrTab = - reinterpret_cast<RemarkStreamer *>(io.getContext())->getStringTable(); - unsigned FileID = StrTab.add(File).first; - io.mapRequired("File", FileID); - } else { - io.mapRequired("File", File); - } - - io.mapRequired("Line", Line); - io.mapRequired("Column", Col); - } - - static const bool flow = true; -}; - -/// Helper struct for multiline string block literals. Use this type to preserve -/// newlines in strings. -struct StringBlockVal { - StringRef Value; - StringBlockVal(const std::string &Value) : Value(Value) {} -}; - -template <> struct BlockScalarTraits<StringBlockVal> { - static void output(const StringBlockVal &S, void *Ctx, raw_ostream &OS) { - return ScalarTraits<StringRef>::output(S.Value, Ctx, OS); - } - - static StringRef input(StringRef Scalar, void *Ctx, StringBlockVal &S) { - return ScalarTraits<StringRef>::input(Scalar, Ctx, S.Value); - } -}; - -// Implement this as a mapping for now to get proper quotation for the value. -template <> struct MappingTraits<DiagnosticInfoOptimizationBase::Argument> { - static void mapping(IO &io, DiagnosticInfoOptimizationBase::Argument &A) { - assert(io.outputting() && "input not yet implemented"); - - if (UseStringTable) { - remarks::StringTable &StrTab = - reinterpret_cast<RemarkStreamer *>(io.getContext())->getStringTable(); - auto ValueID = StrTab.add(A.Val).first; - io.mapRequired(A.Key.data(), ValueID); - } else if (StringRef(A.Val).count('\n') > 1) { - StringBlockVal S(A.Val); - io.mapRequired(A.Key.data(), S); - } else { - io.mapRequired(A.Key.data(), A.Val); - } - if (A.Loc.isValid()) - io.mapOptional("DebugLoc", A.Loc); - } -}; - -} // end namespace yaml -} // end namespace llvm - -LLVM_YAML_IS_SEQUENCE_VECTOR(DiagnosticInfoOptimizationBase::Argument) diff --git a/llvm/lib/IR/RemarkStreamer.cpp b/llvm/lib/IR/RemarkStreamer.cpp index d2a4ed4adf4..fe1a128f473 100644 --- a/llvm/lib/IR/RemarkStreamer.cpp +++ b/llvm/lib/IR/RemarkStreamer.cpp @@ -12,12 +12,15 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/RemarkStreamer.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalValue.h" using namespace llvm; -RemarkStreamer::RemarkStreamer(StringRef Filename, raw_ostream &OS) - : Filename(Filename), OS(OS), - YAMLOutput(OS, reinterpret_cast<void *>(this)), StrTab() { +RemarkStreamer::RemarkStreamer(StringRef Filename, + std::unique_ptr<remarks::Serializer> Serializer) + : Filename(Filename), PassFilter(), Serializer(std::move(Serializer)) { assert(!Filename.empty() && "This needs to be a real filename."); } @@ -31,12 +34,75 @@ Error RemarkStreamer::setFilter(StringRef Filter) { return Error::success(); } +/// DiagnosticKind -> remarks::Type +static remarks::Type toRemarkType(enum DiagnosticKind Kind) { + switch (Kind) { + default: + return remarks::Type::Unknown; + case DK_OptimizationRemark: + case DK_MachineOptimizationRemark: + return remarks::Type::Passed; + case DK_OptimizationRemarkMissed: + case DK_MachineOptimizationRemarkMissed: + return remarks::Type::Missed; + case DK_OptimizationRemarkAnalysis: + case DK_MachineOptimizationRemarkAnalysis: + return remarks::Type::Analysis; + case DK_OptimizationRemarkAnalysisFPCommute: + return remarks::Type::AnalysisFPCommute; + case DK_OptimizationRemarkAnalysisAliasing: + return remarks::Type::AnalysisAliasing; + case DK_OptimizationFailure: + return remarks::Type::Failure; + } +} + +/// DiagnosticLocation -> remarks::RemarkLocation. +static Optional<remarks::RemarkLocation> +toRemarkLocation(const DiagnosticLocation &DL) { + if (!DL.isValid()) + return None; + StringRef File = DL.getRelativePath(); + unsigned Line = DL.getLine(); + unsigned Col = DL.getColumn(); + return remarks::RemarkLocation{File, Line, Col}; +} + +/// LLVM Diagnostic -> Remark +remarks::Remark +RemarkStreamer::toRemark(const DiagnosticInfoOptimizationBase &Diag) { + // Re-use the buffer. + TmpArgs.clear(); + + remarks::Remark R; // The result. + R.RemarkType = toRemarkType(static_cast<DiagnosticKind>(Diag.getKind())); + R.PassName = Diag.getPassName(); + R.RemarkName = Diag.getRemarkName(); + R.FunctionName = + GlobalValue::dropLLVMManglingEscape(Diag.getFunction().getName()); + R.Loc = toRemarkLocation(Diag.getLocation()); + R.Hotness = Diag.getHotness(); + + // Use TmpArgs to build the list of arguments and re-use the memory allocated + // from previous remark conversions. + for (const DiagnosticInfoOptimizationBase::Argument &Arg : Diag.getArgs()) { + TmpArgs.emplace_back(); + TmpArgs.back().Key = Arg.Key; + TmpArgs.back().Val = Arg.Val; + TmpArgs.back().Loc = toRemarkLocation(Arg.Loc); + } + R.Args = TmpArgs; // This is valid until the next call to this function. + + return R; +} + void RemarkStreamer::emit(const DiagnosticInfoOptimizationBase &Diag) { if (Optional<Regex> &Filter = PassFilter) if (!Filter->match(Diag.getPassName())) return; - DiagnosticInfoOptimizationBase *DiagPtr = - const_cast<DiagnosticInfoOptimizationBase *>(&Diag); - YAMLOutput << DiagPtr; + // First, convert the diagnostic to a remark. + remarks::Remark R = toRemark(Diag); + // Then, emit the remark through the serializer. + Serializer->emit(R); } diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index ce1b0a1e4f6..882b15525c1 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -1356,8 +1356,9 @@ lto::setupOptimizationRemarks(LLVMContext &Context, llvm::make_unique<ToolOutputFile>(Filename, EC, sys::fs::F_None); if (EC) return errorCodeToError(EC); - Context.setRemarkStreamer( - llvm::make_unique<RemarkStreamer>(Filename, DiagnosticFile->os())); + Context.setRemarkStreamer(llvm::make_unique<RemarkStreamer>( + Filename, + llvm::make_unique<remarks::YAMLSerializer>(DiagnosticFile->os()))); if (!LTORemarksPasses.empty()) if (Error E = Context.getRemarkStreamer()->setFilter(LTORemarksPasses)) diff --git a/llvm/lib/Remarks/CMakeLists.txt b/llvm/lib/Remarks/CMakeLists.txt index ccbca7ea4f4..73383597acc 100644 --- a/llvm/lib/Remarks/CMakeLists.txt +++ b/llvm/lib/Remarks/CMakeLists.txt @@ -3,4 +3,5 @@ add_llvm_library(LLVMRemarks RemarkParser.cpp RemarkStringTable.cpp YAMLRemarkParser.cpp + YAMLRemarkSerializer.cpp ) diff --git a/llvm/lib/Remarks/YAMLRemarkSerializer.cpp b/llvm/lib/Remarks/YAMLRemarkSerializer.cpp new file mode 100644 index 00000000000..47fef5dd2ae --- /dev/null +++ b/llvm/lib/Remarks/YAMLRemarkSerializer.cpp @@ -0,0 +1,166 @@ +//===- YAMLRemarkSerializer.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 the implementation of the YAML remark serializer using +// LLVM's YAMLTraits. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Remarks/RemarkSerializer.h" +#include "llvm/Support/CommandLine.h" + +using namespace llvm; +using namespace llvm::remarks; + +cl::opt<bool> RemarksYAMLStringTable("remarks-yaml-string-table", + cl::init(false)); + +// Use the same keys whether we use a string table or not (respectively, T is an +// unsigned or a StringRef). +template <typename T> +static void mapRemarkHeader(yaml::IO &io, T PassName, T RemarkName, + Optional<RemarkLocation> RL, T FunctionName, + Optional<uint64_t> Hotness, + ArrayRef<Argument> Args) { + io.mapRequired("Pass", PassName); + io.mapRequired("Name", RemarkName); + io.mapOptional("DebugLoc", RL); + io.mapRequired("Function", FunctionName); + io.mapOptional("Hotness", Hotness); + io.mapOptional("Args", Args); +} + +namespace llvm { +namespace yaml { + +template <> struct MappingTraits<remarks::Remark *> { + static void mapping(IO &io, remarks::Remark *&Remark) { + assert(io.outputting() && "input not yet implemented"); + + if (io.mapTag("!Passed", (Remark->RemarkType == Type::Passed))) + ; + else if (io.mapTag("!Missed", (Remark->RemarkType == Type::Missed))) + ; + else if (io.mapTag("!Analysis", (Remark->RemarkType == Type::Analysis))) + ; + else if (io.mapTag("!AnalysisFPCommute", + (Remark->RemarkType == Type::AnalysisFPCommute))) + ; + else if (io.mapTag("!AnalysisAliasing", + (Remark->RemarkType == Type::AnalysisAliasing))) + ; + else if (io.mapTag("!Failure", (Remark->RemarkType == Type::Failure))) + ; + else + llvm_unreachable("Unknown remark type"); + + if (Optional<StringTable> &StrTab = + reinterpret_cast<YAMLSerializer *>(io.getContext())->StrTab) { + unsigned PassID = StrTab->add(Remark->PassName).first; + unsigned NameID = StrTab->add(Remark->RemarkName).first; + unsigned FunctionID = StrTab->add(Remark->FunctionName).first; + mapRemarkHeader(io, PassID, NameID, Remark->Loc, FunctionID, + Remark->Hotness, Remark->Args); + } else { + mapRemarkHeader(io, Remark->PassName, Remark->RemarkName, Remark->Loc, + Remark->FunctionName, Remark->Hotness, Remark->Args); + } + } +}; + +template <> struct MappingTraits<RemarkLocation> { + static void mapping(IO &io, RemarkLocation &RL) { + assert(io.outputting() && "input not yet implemented"); + + StringRef File = RL.SourceFilePath; + unsigned Line = RL.SourceLine; + unsigned Col = RL.SourceColumn; + + if (Optional<StringTable> &StrTab = + reinterpret_cast<YAMLSerializer *>(io.getContext())->StrTab) { + unsigned FileID = StrTab->add(File).first; + io.mapRequired("File", FileID); + } else { + io.mapRequired("File", File); + } + + io.mapRequired("Line", Line); + io.mapRequired("Column", Col); + } + + static const bool flow = true; +}; + +/// Helper struct for multiline string block literals. Use this type to preserve +/// newlines in strings. +struct StringBlockVal { + StringRef Value; + StringBlockVal(const std::string &Value) : Value(Value) {} +}; + +template <> struct BlockScalarTraits<StringBlockVal> { + static void output(const StringBlockVal &S, void *Ctx, raw_ostream &OS) { + return ScalarTraits<StringRef>::output(S.Value, Ctx, OS); + } + + static StringRef input(StringRef Scalar, void *Ctx, StringBlockVal &S) { + return ScalarTraits<StringRef>::input(Scalar, Ctx, S.Value); + } +}; + +/// ArrayRef is not really compatible with the YAMLTraits. Everything should be +/// immutable in an ArrayRef, while the SequenceTraits expect a mutable version +/// for inputting, but we're only using the outputting capabilities here. +/// This is a hack, but still nicer than having to manually call the YAMLIO +/// internal methods. +/// Keep this in this file so that it doesn't get misused from YAMLTraits.h. +template <typename T> struct SequenceTraits<ArrayRef<T>> { + static size_t size(IO &io, ArrayRef<T> &seq) { return seq.size(); } + static Argument &element(IO &io, ArrayRef<T> &seq, size_t index) { + assert(io.outputting() && "input not yet implemented"); + // The assert above should make this "safer" to satisfy the YAMLTraits. + return const_cast<T &>(seq[index]); + } +}; + +/// Implement this as a mapping for now to get proper quotation for the value. +template <> struct MappingTraits<Argument> { + static void mapping(IO &io, Argument &A) { + assert(io.outputting() && "input not yet implemented"); + + if (Optional<StringTable> &StrTab = + reinterpret_cast<YAMLSerializer *>(io.getContext())->StrTab) { + auto ValueID = StrTab->add(A.Val).first; + io.mapRequired(A.Key.data(), ValueID); + } else if (StringRef(A.Val).count('\n') > 1) { + StringBlockVal S(A.Val); + io.mapRequired(A.Key.data(), S); + } else { + io.mapRequired(A.Key.data(), A.Val); + } + io.mapOptional("DebugLoc", A.Loc); + } +}; + +} // end namespace yaml +} // end namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(Argument) + +YAMLSerializer::YAMLSerializer(raw_ostream &OS, UseStringTable UseStringTable) + : Serializer(OS), YAMLOutput(OS, reinterpret_cast<void *>(this)) { + if (UseStringTable == UseStringTable::Yes || RemarksYAMLStringTable) + StrTab.emplace(); +} + +void YAMLSerializer::emit(const Remark &Remark) { + // Again, YAMLTraits expect a non-const object for inputting, but we're not + // using that here. + auto R = const_cast<remarks::Remark *>(&Remark); + YAMLOutput << R; +} diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp index be103845e97..66c5cd0ad43 100644 --- a/llvm/tools/llc/llc.cpp +++ b/llvm/tools/llc/llc.cpp @@ -340,8 +340,9 @@ int main(int argc, char **argv) { WithColor::error(errs(), argv[0]) << EC.message() << '\n'; return 1; } - Context.setRemarkStreamer( - llvm::make_unique<RemarkStreamer>(RemarksFilename, YamlFile->os())); + Context.setRemarkStreamer(llvm::make_unique<RemarkStreamer>( + RemarksFilename, + llvm::make_unique<remarks::YAMLSerializer>(YamlFile->os()))); if (!RemarksPasses.empty()) if (Error E = Context.getRemarkStreamer()->setFilter(RemarksPasses)) { diff --git a/llvm/tools/opt/opt.cpp b/llvm/tools/opt/opt.cpp index 2119cc0183f..7053c2deb37 100644 --- a/llvm/tools/opt/opt.cpp +++ b/llvm/tools/opt/opt.cpp @@ -563,7 +563,8 @@ int main(int argc, char **argv) { return 1; } Context.setRemarkStreamer(llvm::make_unique<RemarkStreamer>( - RemarksFilename, OptRemarkFile->os())); + RemarksFilename, + llvm::make_unique<remarks::YAMLSerializer>(OptRemarkFile->os()))); if (!RemarksPasses.empty()) if (Error E = Context.getRemarkStreamer()->setFilter(RemarksPasses)) { |

