Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Remarks/YAMLRemarkSerializer.cpp
35262 views
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/YAMLRemarkSerializer.h"
15
#include "llvm/Remarks/Remark.h"
16
#include "llvm/Support/FileSystem.h"
17
#include <optional>
18
19
using namespace llvm;
20
using namespace llvm::remarks;
21
22
// Use the same keys whether we use a string table or not (respectively, T is an
23
// unsigned or a StringRef).
24
template <typename T>
25
static void mapRemarkHeader(yaml::IO &io, T PassName, T RemarkName,
26
std::optional<RemarkLocation> RL, T FunctionName,
27
std::optional<uint64_t> Hotness,
28
ArrayRef<Argument> Args) {
29
io.mapRequired("Pass", PassName);
30
io.mapRequired("Name", RemarkName);
31
io.mapOptional("DebugLoc", RL);
32
io.mapRequired("Function", FunctionName);
33
io.mapOptional("Hotness", Hotness);
34
io.mapOptional("Args", Args);
35
}
36
37
namespace llvm {
38
namespace yaml {
39
40
template <> struct MappingTraits<remarks::Remark *> {
41
static void mapping(IO &io, remarks::Remark *&Remark) {
42
assert(io.outputting() && "input not yet implemented");
43
44
if (io.mapTag("!Passed", (Remark->RemarkType == Type::Passed)))
45
;
46
else if (io.mapTag("!Missed", (Remark->RemarkType == Type::Missed)))
47
;
48
else if (io.mapTag("!Analysis", (Remark->RemarkType == Type::Analysis)))
49
;
50
else if (io.mapTag("!AnalysisFPCommute",
51
(Remark->RemarkType == Type::AnalysisFPCommute)))
52
;
53
else if (io.mapTag("!AnalysisAliasing",
54
(Remark->RemarkType == Type::AnalysisAliasing)))
55
;
56
else if (io.mapTag("!Failure", (Remark->RemarkType == Type::Failure)))
57
;
58
else
59
llvm_unreachable("Unknown remark type");
60
61
if (auto *Serializer = dyn_cast<YAMLStrTabRemarkSerializer>(
62
reinterpret_cast<RemarkSerializer *>(io.getContext()))) {
63
assert(Serializer->StrTab && "YAMLStrTabSerializer with no StrTab.");
64
StringTable &StrTab = *Serializer->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 (auto *Serializer = dyn_cast<YAMLStrTabRemarkSerializer>(
86
reinterpret_cast<RemarkSerializer *>(io.getContext()))) {
87
assert(Serializer->StrTab && "YAMLStrTabSerializer with no StrTab.");
88
StringTable &StrTab = *Serializer->StrTab;
89
unsigned FileID = StrTab.add(File).first;
90
io.mapRequired("File", FileID);
91
} else {
92
io.mapRequired("File", File);
93
}
94
95
io.mapRequired("Line", Line);
96
io.mapRequired("Column", Col);
97
}
98
99
static const bool flow = true;
100
};
101
102
/// Helper struct for multiline string block literals. Use this type to preserve
103
/// newlines in strings.
104
struct StringBlockVal {
105
StringRef Value;
106
StringBlockVal(StringRef R) : Value(R) {}
107
};
108
109
template <> struct BlockScalarTraits<StringBlockVal> {
110
static void output(const StringBlockVal &S, void *Ctx, raw_ostream &OS) {
111
return ScalarTraits<StringRef>::output(S.Value, Ctx, OS);
112
}
113
114
static StringRef input(StringRef Scalar, void *Ctx, StringBlockVal &S) {
115
return ScalarTraits<StringRef>::input(Scalar, Ctx, S.Value);
116
}
117
};
118
119
/// ArrayRef is not really compatible with the YAMLTraits. Everything should be
120
/// immutable in an ArrayRef, while the SequenceTraits expect a mutable version
121
/// for inputting, but we're only using the outputting capabilities here.
122
/// This is a hack, but still nicer than having to manually call the YAMLIO
123
/// internal methods.
124
/// Keep this in this file so that it doesn't get misused from YAMLTraits.h.
125
template <typename T> struct SequenceTraits<ArrayRef<T>> {
126
static size_t size(IO &io, ArrayRef<T> &seq) { return seq.size(); }
127
static Argument &element(IO &io, ArrayRef<T> &seq, size_t index) {
128
assert(io.outputting() && "input not yet implemented");
129
// The assert above should make this "safer" to satisfy the YAMLTraits.
130
return const_cast<T &>(seq[index]);
131
}
132
};
133
134
/// Implement this as a mapping for now to get proper quotation for the value.
135
template <> struct MappingTraits<Argument> {
136
static void mapping(IO &io, Argument &A) {
137
assert(io.outputting() && "input not yet implemented");
138
139
if (auto *Serializer = dyn_cast<YAMLStrTabRemarkSerializer>(
140
reinterpret_cast<RemarkSerializer *>(io.getContext()))) {
141
assert(Serializer->StrTab && "YAMLStrTabSerializer with no StrTab.");
142
StringTable &StrTab = *Serializer->StrTab;
143
auto ValueID = StrTab.add(A.Val).first;
144
io.mapRequired(A.Key.data(), ValueID);
145
} else if (StringRef(A.Val).count('\n') > 1) {
146
StringBlockVal S(A.Val);
147
io.mapRequired(A.Key.data(), S);
148
} else {
149
io.mapRequired(A.Key.data(), A.Val);
150
}
151
io.mapOptional("DebugLoc", A.Loc);
152
}
153
};
154
155
} // end namespace yaml
156
} // end namespace llvm
157
158
LLVM_YAML_IS_SEQUENCE_VECTOR(Argument)
159
160
YAMLRemarkSerializer::YAMLRemarkSerializer(raw_ostream &OS, SerializerMode Mode,
161
std::optional<StringTable> StrTabIn)
162
: YAMLRemarkSerializer(Format::YAML, OS, Mode, std::move(StrTabIn)) {}
163
164
YAMLRemarkSerializer::YAMLRemarkSerializer(Format SerializerFormat,
165
raw_ostream &OS, SerializerMode Mode,
166
std::optional<StringTable> StrTabIn)
167
: RemarkSerializer(SerializerFormat, OS, Mode),
168
YAMLOutput(OS, reinterpret_cast<void *>(this)) {
169
StrTab = std::move(StrTabIn);
170
}
171
172
void YAMLRemarkSerializer::emit(const Remark &Remark) {
173
// Again, YAMLTraits expect a non-const object for inputting, but we're not
174
// using that here.
175
auto R = const_cast<remarks::Remark *>(&Remark);
176
YAMLOutput << R;
177
}
178
179
std::unique_ptr<MetaSerializer> YAMLRemarkSerializer::metaSerializer(
180
raw_ostream &OS, std::optional<StringRef> ExternalFilename) {
181
return std::make_unique<YAMLMetaSerializer>(OS, ExternalFilename);
182
}
183
184
void YAMLStrTabRemarkSerializer::emit(const Remark &Remark) {
185
// In standalone mode, for the serializer with a string table, emit the
186
// metadata first and set DidEmitMeta to avoid emitting it again.
187
if (Mode == SerializerMode::Standalone && !DidEmitMeta) {
188
std::unique_ptr<MetaSerializer> MetaSerializer =
189
metaSerializer(OS, /*ExternalFilename=*/std::nullopt);
190
MetaSerializer->emit();
191
DidEmitMeta = true;
192
}
193
194
// Then do the usual remark emission.
195
YAMLRemarkSerializer::emit(Remark);
196
}
197
198
std::unique_ptr<MetaSerializer> YAMLStrTabRemarkSerializer::metaSerializer(
199
raw_ostream &OS, std::optional<StringRef> ExternalFilename) {
200
assert(StrTab);
201
return std::make_unique<YAMLStrTabMetaSerializer>(OS, ExternalFilename,
202
*StrTab);
203
}
204
205
static void emitMagic(raw_ostream &OS) {
206
// Emit the magic number.
207
OS << remarks::Magic;
208
// Explicitly emit a '\0'.
209
OS.write('\0');
210
}
211
212
static void emitVersion(raw_ostream &OS) {
213
// Emit the version number: little-endian uint64_t.
214
std::array<char, 8> Version;
215
support::endian::write64le(Version.data(), remarks::CurrentRemarkVersion);
216
OS.write(Version.data(), Version.size());
217
}
218
219
static void emitStrTab(raw_ostream &OS,
220
std::optional<const StringTable *> StrTab) {
221
// Emit the string table in the section.
222
uint64_t StrTabSize = StrTab ? (*StrTab)->SerializedSize : 0;
223
// Emit the total size of the string table (the size itself excluded):
224
// little-endian uint64_t.
225
// Note: even if no string table is used, emit 0.
226
std::array<char, 8> StrTabSizeBuf;
227
support::endian::write64le(StrTabSizeBuf.data(), StrTabSize);
228
OS.write(StrTabSizeBuf.data(), StrTabSizeBuf.size());
229
if (StrTab)
230
(*StrTab)->serialize(OS);
231
}
232
233
static void emitExternalFile(raw_ostream &OS, StringRef Filename) {
234
// Emit the null-terminated absolute path to the remark file.
235
SmallString<128> FilenameBuf = Filename;
236
sys::fs::make_absolute(FilenameBuf);
237
assert(!FilenameBuf.empty() && "The filename can't be empty.");
238
OS.write(FilenameBuf.data(), FilenameBuf.size());
239
OS.write('\0');
240
}
241
242
void YAMLMetaSerializer::emit() {
243
emitMagic(OS);
244
emitVersion(OS);
245
emitStrTab(OS, std::nullopt);
246
if (ExternalFilename)
247
emitExternalFile(OS, *ExternalFilename);
248
}
249
250
void YAMLStrTabMetaSerializer::emit() {
251
emitMagic(OS);
252
emitVersion(OS);
253
emitStrTab(OS, &StrTab);
254
if (ExternalFilename)
255
emitExternalFile(OS, *ExternalFilename);
256
}
257
258