//===- 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 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 static void mapRemarkHeader(yaml::IO &io, T PassName, T RemarkName, Optional RL, T FunctionName, Optional Hotness, ArrayRef 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 { 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 &StrTab = reinterpret_cast(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 { 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 &StrTab = reinterpret_cast(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 { static void output(const StringBlockVal &S, void *Ctx, raw_ostream &OS) { return ScalarTraits::output(S.Value, Ctx, OS); } static StringRef input(StringRef Scalar, void *Ctx, StringBlockVal &S) { return ScalarTraits::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 struct SequenceTraits> { static size_t size(IO &io, ArrayRef &seq) { return seq.size(); } static Argument &element(IO &io, ArrayRef &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(seq[index]); } }; /// Implement this as a mapping for now to get proper quotation for the value. template <> struct MappingTraits { static void mapping(IO &io, Argument &A) { assert(io.outputting() && "input not yet implemented"); if (Optional &StrTab = reinterpret_cast(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(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(&Remark); YAMLOutput << R; }