diff options
Diffstat (limited to 'lib/Remarks/YAMLRemarkSerializer.cpp')
-rw-r--r-- | lib/Remarks/YAMLRemarkSerializer.cpp | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/lib/Remarks/YAMLRemarkSerializer.cpp b/lib/Remarks/YAMLRemarkSerializer.cpp new file mode 100644 index 000000000000..d64ae8e12ab0 --- /dev/null +++ b/lib/Remarks/YAMLRemarkSerializer.cpp @@ -0,0 +1,167 @@ +//===- 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), cl::Hidden, + cl::desc("Enable the usage of a string table with YAML remarks.")); + +// 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 == remarks::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; +} |