1 //===- YAMLRemarkSerializer.cpp -------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file provides the implementation of the YAML remark serializer using 10 // LLVM's YAMLTraits. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/Remarks/RemarkSerializer.h" 15 #include "llvm/Support/CommandLine.h" 16 17 using namespace llvm; 18 using namespace llvm::remarks; 19 20 cl::opt<bool> RemarksYAMLStringTable( 21 "remarks-yaml-string-table", cl::init(false), cl::Hidden, 22 cl::desc("Enable the usage of a string table with YAML remarks.")); 23 24 // Use the same keys whether we use a string table or not (respectively, T is an 25 // unsigned or a StringRef). 26 template <typename T> 27 static void mapRemarkHeader(yaml::IO &io, T PassName, T RemarkName, 28 Optional<RemarkLocation> RL, T FunctionName, 29 Optional<uint64_t> Hotness, 30 ArrayRef<Argument> Args) { 31 io.mapRequired("Pass", PassName); 32 io.mapRequired("Name", RemarkName); 33 io.mapOptional("DebugLoc", RL); 34 io.mapRequired("Function", FunctionName); 35 io.mapOptional("Hotness", Hotness); 36 io.mapOptional("Args", Args); 37 } 38 39 namespace llvm { 40 namespace yaml { 41 42 template <> struct MappingTraits<remarks::Remark *> { 43 static void mapping(IO &io, remarks::Remark *&Remark) { 44 assert(io.outputting() && "input not yet implemented"); 45 46 if (io.mapTag("!Passed", (Remark->RemarkType == Type::Passed))) 47 ; 48 else if (io.mapTag("!Missed", (Remark->RemarkType == Type::Missed))) 49 ; 50 else if (io.mapTag("!Analysis", (Remark->RemarkType == Type::Analysis))) 51 ; 52 else if (io.mapTag("!AnalysisFPCommute", 53 (Remark->RemarkType == Type::AnalysisFPCommute))) 54 ; 55 else if (io.mapTag("!AnalysisAliasing", 56 (Remark->RemarkType == Type::AnalysisAliasing))) 57 ; 58 else if (io.mapTag("!Failure", (Remark->RemarkType == Type::Failure))) 59 ; 60 else 61 llvm_unreachable("Unknown remark type"); 62 63 if (Optional<StringTable> &StrTab = 64 reinterpret_cast<YAMLSerializer *>(io.getContext())->StrTab) { 65 unsigned PassID = StrTab->add(Remark->PassName).first; 66 unsigned NameID = StrTab->add(Remark->RemarkName).first; 67 unsigned FunctionID = StrTab->add(Remark->FunctionName).first; 68 mapRemarkHeader(io, PassID, NameID, Remark->Loc, FunctionID, 69 Remark->Hotness, Remark->Args); 70 } else { 71 mapRemarkHeader(io, Remark->PassName, Remark->RemarkName, Remark->Loc, 72 Remark->FunctionName, Remark->Hotness, Remark->Args); 73 } 74 } 75 }; 76 77 template <> struct MappingTraits<RemarkLocation> { 78 static void mapping(IO &io, RemarkLocation &RL) { 79 assert(io.outputting() && "input not yet implemented"); 80 81 StringRef File = RL.SourceFilePath; 82 unsigned Line = RL.SourceLine; 83 unsigned Col = RL.SourceColumn; 84 85 if (Optional<StringTable> &StrTab = 86 reinterpret_cast<YAMLSerializer *>(io.getContext())->StrTab) { 87 unsigned FileID = StrTab->add(File).first; 88 io.mapRequired("File", FileID); 89 } else { 90 io.mapRequired("File", File); 91 } 92 93 io.mapRequired("Line", Line); 94 io.mapRequired("Column", Col); 95 } 96 97 static const bool flow = true; 98 }; 99 100 /// Helper struct for multiline string block literals. Use this type to preserve 101 /// newlines in strings. 102 struct StringBlockVal { 103 StringRef Value; 104 StringBlockVal(const std::string &Value) : Value(Value) {} 105 }; 106 107 template <> struct BlockScalarTraits<StringBlockVal> { 108 static void output(const StringBlockVal &S, void *Ctx, raw_ostream &OS) { 109 return ScalarTraits<StringRef>::output(S.Value, Ctx, OS); 110 } 111 112 static StringRef input(StringRef Scalar, void *Ctx, StringBlockVal &S) { 113 return ScalarTraits<StringRef>::input(Scalar, Ctx, S.Value); 114 } 115 }; 116 117 /// ArrayRef is not really compatible with the YAMLTraits. Everything should be 118 /// immutable in an ArrayRef, while the SequenceTraits expect a mutable version 119 /// for inputting, but we're only using the outputting capabilities here. 120 /// This is a hack, but still nicer than having to manually call the YAMLIO 121 /// internal methods. 122 /// Keep this in this file so that it doesn't get misused from YAMLTraits.h. 123 template <typename T> struct SequenceTraits<ArrayRef<T>> { 124 static size_t size(IO &io, ArrayRef<T> &seq) { return seq.size(); } 125 static Argument &element(IO &io, ArrayRef<T> &seq, size_t index) { 126 assert(io.outputting() && "input not yet implemented"); 127 // The assert above should make this "safer" to satisfy the YAMLTraits. 128 return const_cast<T &>(seq[index]); 129 } 130 }; 131 132 /// Implement this as a mapping for now to get proper quotation for the value. 133 template <> struct MappingTraits<Argument> { 134 static void mapping(IO &io, Argument &A) { 135 assert(io.outputting() && "input not yet implemented"); 136 137 if (Optional<StringTable> &StrTab = 138 reinterpret_cast<YAMLSerializer *>(io.getContext())->StrTab) { 139 auto ValueID = StrTab->add(A.Val).first; 140 io.mapRequired(A.Key.data(), ValueID); 141 } else if (StringRef(A.Val).count('\n') > 1) { 142 StringBlockVal S(A.Val); 143 io.mapRequired(A.Key.data(), S); 144 } else { 145 io.mapRequired(A.Key.data(), A.Val); 146 } 147 io.mapOptional("DebugLoc", A.Loc); 148 } 149 }; 150 151 } // end namespace yaml 152 } // end namespace llvm 153 154 LLVM_YAML_IS_SEQUENCE_VECTOR(Argument) 155 156 YAMLSerializer::YAMLSerializer(raw_ostream &OS, UseStringTable UseStringTable) 157 : Serializer(OS), YAMLOutput(OS, reinterpret_cast<void *>(this)) { 158 if (UseStringTable == remarks::UseStringTable::Yes || RemarksYAMLStringTable) 159 StrTab.emplace(); 160 } 161 162 void YAMLSerializer::emit(const Remark &Remark) { 163 // Again, YAMLTraits expect a non-const object for inputting, but we're not 164 // using that here. 165 auto R = const_cast<remarks::Remark *>(&Remark); 166 YAMLOutput << R; 167 } 168