1//===- unittest/Support/BitstreamRemarksSerializerTest.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#include "llvm/Bitcode/BitcodeAnalyzer.h"
10#include "llvm/Remarks/BitstreamRemarkSerializer.h"
11#include "llvm/Remarks/Remark.h"
12#include "llvm/Support/raw_ostream.h"
13#include "gtest/gtest.h"
14#include <optional>
15#include <string>
16
17// We need to supprt Windows paths as well. In order to have paths with the same
18// length, use a different path according to the platform.
19#ifdef _WIN32
20#define EXTERNALFILETESTPATH "C:/externalfi"
21#else
22#define EXTERNALFILETESTPATH "/externalfile"
23#endif
24
25using namespace llvm;
26
27static void checkAnalyze(StringRef Input, StringRef Expected) {
28 std::string OutputBuf;
29 raw_string_ostream OutputOS(OutputBuf);
30 BCDumpOptions O(OutputOS);
31 O.ShowBinaryBlobs = true;
32 BitcodeAnalyzer BA(Input);
33 EXPECT_FALSE(BA.analyze(O)); // Expect no errors.
34 EXPECT_EQ(OutputOS.str(), Expected);
35}
36
37static void check(remarks::SerializerMode Mode, const remarks::Remark &R,
38 StringRef ExpectedR, std::optional<StringRef> ExpectedMeta,
39 std::optional<remarks::StringTable> StrTab) {
40 // Emit the remark.
41 std::string InputBuf;
42 raw_string_ostream InputOS(InputBuf);
43 Expected<std::unique_ptr<remarks::RemarkSerializer>> MaybeSerializer = [&] {
44 if (StrTab)
45 return createRemarkSerializer(RemarksFormat: remarks::Format::Bitstream, Mode, OS&: InputOS,
46 StrTab: std::move(*StrTab));
47 else
48 return createRemarkSerializer(RemarksFormat: remarks::Format::Bitstream, Mode, OS&: InputOS);
49 }();
50 EXPECT_FALSE(errorToBool(MaybeSerializer.takeError()));
51 std::unique_ptr<remarks::RemarkSerializer> Serializer =
52 std::move(*MaybeSerializer);
53 Serializer->emit(Remark: R);
54
55 // Analyze the serialized remark.
56 checkAnalyze(Input: InputOS.str(), Expected: ExpectedR);
57
58 // Analyze the serialized metadata if it's not in standalone mode.
59 if (ExpectedMeta) {
60 std::string MetaBuf;
61 raw_string_ostream MetaOS(MetaBuf);
62 std::unique_ptr<remarks::MetaSerializer> MetaSerializer =
63 Serializer->metaSerializer(OS&: MetaOS, ExternalFilename: StringRef(EXTERNALFILETESTPATH));
64 MetaSerializer->emit();
65 checkAnalyze(Input: MetaOS.str(), Expected: *ExpectedMeta);
66 }
67}
68
69static void check(const remarks::Remark &R, StringRef ExpectedR,
70 StringRef ExpectedMeta,
71 std::optional<remarks::StringTable> StrTab = std::nullopt) {
72 return check(Mode: remarks::SerializerMode::Separate, R, ExpectedR, ExpectedMeta,
73 StrTab: std::move(StrTab));
74}
75
76static void
77checkStandalone(const remarks::Remark &R, StringRef ExpectedR,
78 std::optional<remarks::StringTable> StrTab = std::nullopt) {
79 return check(Mode: remarks::SerializerMode::Standalone, R, ExpectedR,
80 /*ExpectedMeta=*/std::nullopt, StrTab: std::move(StrTab));
81}
82
83TEST(BitstreamRemarkSerializer, SeparateRemarkFileNoOptionals) {
84 remarks::Remark R;
85 R.RemarkType = remarks::Type::Missed;
86 R.PassName = "pass";
87 R.RemarkName = "remark";
88 R.FunctionName = "function";
89 check(R,
90 ExpectedR: "<BLOCKINFO_BLOCK/>\n"
91 "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
92 " <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n"
93 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"
94 "</Meta>\n"
95 "<Remark BlockID=9 NumWords=1 BlockCodeSize=4>\n"
96 " <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n"
97 "</Remark>\n",
98 ExpectedMeta: "<BLOCKINFO_BLOCK/>\n"
99 "<Meta BlockID=8 NumWords=14 BlockCodeSize=3>\n"
100 " <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n"
101 " <String table codeid=3 abbrevid=5/> blob data = "
102 "'remark\\x00pass\\x00function\\x00'\n"
103 " <External File codeid=4 abbrevid=6/> blob data = "
104 "'" EXTERNALFILETESTPATH"'\n"
105 "</Meta>\n");
106}
107
108TEST(BitstreamRemarkSerializer, SeparateRemarkFileNoOptionalsSeparateStrTab) {
109 remarks::StringTable StrTab;
110 StrTab.add(Str: "function");
111 StrTab.add(Str: "pass");
112 StrTab.add(Str: "remark");
113 remarks::Remark R;
114 R.RemarkType = remarks::Type::Missed;
115 R.PassName = "pass";
116 R.RemarkName = "remark";
117 R.FunctionName = "function";
118 check(R,
119 ExpectedR: "<BLOCKINFO_BLOCK/>\n"
120 "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
121 " <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n"
122 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"
123 "</Meta>\n"
124 "<Remark BlockID=9 NumWords=1 BlockCodeSize=4>\n"
125 " <Remark header codeid=5 abbrevid=4 op0=2 op1=2 op2=1 op3=0/>\n"
126 "</Remark>\n",
127 ExpectedMeta: "<BLOCKINFO_BLOCK/>\n"
128 "<Meta BlockID=8 NumWords=14 BlockCodeSize=3>\n"
129 " <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n"
130 " <String table codeid=3 abbrevid=5/> blob data = "
131 "'function\\x00pass\\x00remark\\x00'\n"
132 " <External File codeid=4 abbrevid=6/> blob data = "
133 "'" EXTERNALFILETESTPATH"'\n"
134 "</Meta>\n",
135 StrTab: std::move(StrTab));
136}
137
138TEST(BitstreamRemarkSerializer, SeparateRemarkFileDebugLoc) {
139 remarks::Remark R;
140 R.RemarkType = remarks::Type::Missed;
141 R.PassName = "pass";
142 R.RemarkName = "remark";
143 R.FunctionName = "function";
144 R.Loc.emplace();
145 R.Loc->SourceFilePath = "path";
146 R.Loc->SourceLine = 99;
147 R.Loc->SourceColumn = 55;
148 check(R,
149 ExpectedR: "<BLOCKINFO_BLOCK/>\n"
150 "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
151 " <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n"
152 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"
153 "</Meta>\n"
154 "<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
155 " <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n"
156 " <Remark debug location codeid=6 abbrevid=5 op0=3 op1=99 op2=55/>\n"
157 "</Remark>\n",
158 ExpectedMeta: "<BLOCKINFO_BLOCK/>\n"
159 "<Meta BlockID=8 NumWords=15 BlockCodeSize=3>\n"
160 " <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n"
161 " <String table codeid=3 abbrevid=5/> blob data = "
162 "'remark\\x00pass\\x00function\\x00path\\x00'\n"
163 " <External File codeid=4 abbrevid=6/> blob data = "
164 "'" EXTERNALFILETESTPATH"'\n"
165 "</Meta>\n");
166}
167
168TEST(BitstreamRemarkSerializer, SeparateRemarkFileHotness) {
169 remarks::Remark R;
170 R.RemarkType = remarks::Type::Missed;
171 R.PassName = "pass";
172 R.RemarkName = "remark";
173 R.FunctionName = "function";
174 R.Hotness.emplace(args: 999999999);
175 check(R,
176 ExpectedR: "<BLOCKINFO_BLOCK/>\n"
177 "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
178 " <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n"
179 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"
180 "</Meta>\n"
181 "<Remark BlockID=9 NumWords=3 BlockCodeSize=4>\n"
182 " <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n"
183 " <Remark hotness codeid=7 abbrevid=6 op0=999999999/>\n"
184 "</Remark>\n",
185 ExpectedMeta: "<BLOCKINFO_BLOCK/>\n"
186 "<Meta BlockID=8 NumWords=14 BlockCodeSize=3>\n"
187 " <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n"
188 " <String table codeid=3 abbrevid=5/> blob data = "
189 "'remark\\x00pass\\x00function\\x00'\n"
190 " <External File codeid=4 abbrevid=6/> blob data = "
191 "'" EXTERNALFILETESTPATH"'\n"
192 "</Meta>\n");
193}
194
195TEST(BitstreamRemarkSerializer, SeparateRemarkFileArgNoDebugLoc) {
196 remarks::Remark R;
197 R.RemarkType = remarks::Type::Missed;
198 R.PassName = "pass";
199 R.RemarkName = "remark";
200 R.FunctionName = "function";
201 R.Args.emplace_back();
202 R.Args.back().Key = "key";
203 R.Args.back().Val = "value";
204 check(R,
205 ExpectedR: "<BLOCKINFO_BLOCK/>\n"
206 "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
207 " <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n"
208 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"
209 "</Meta>\n"
210 "<Remark BlockID=9 NumWords=2 BlockCodeSize=4>\n"
211 " <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n"
212 " <Argument codeid=9 abbrevid=8 op0=3 op1=4/>\n"
213 "</Remark>\n",
214 ExpectedMeta: "<BLOCKINFO_BLOCK/>\n"
215 "<Meta BlockID=8 NumWords=16 BlockCodeSize=3>\n"
216 " <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n"
217 " <String table codeid=3 abbrevid=5/> blob data = "
218 "'remark\\x00pass\\x00function\\x00key\\x00value\\x00'\n"
219 " <External File codeid=4 abbrevid=6/> blob data = "
220 "'" EXTERNALFILETESTPATH"'\n"
221 "</Meta>\n");
222}
223
224TEST(BitstreamRemarkSerializer, SeparateRemarkFileArgDebugLoc) {
225 remarks::Remark R;
226 R.RemarkType = remarks::Type::Missed;
227 R.PassName = "pass";
228 R.RemarkName = "remark";
229 R.FunctionName = "function";
230 R.Args.emplace_back();
231 R.Args.back().Key = "key";
232 R.Args.back().Val = "value";
233 R.Args.back().Loc.emplace();
234 R.Args.back().Loc->SourceFilePath = "path";
235 R.Args.back().Loc->SourceLine = 99;
236 R.Args.back().Loc->SourceColumn = 55;
237 check(R,
238 ExpectedR: "<BLOCKINFO_BLOCK/>\n"
239 "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
240 " <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n"
241 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"
242 "</Meta>\n"
243 "<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
244 " <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n"
245 " <Argument with debug location codeid=8 abbrevid=7 op0=3 op1=4 op2=5 "
246 "op3=99 op4=55/>\n"
247 "</Remark>\n",
248 ExpectedMeta: "<BLOCKINFO_BLOCK/>\n"
249 "<Meta BlockID=8 NumWords=17 BlockCodeSize=3>\n"
250 " <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n"
251 " <String table codeid=3 abbrevid=5/> blob data = "
252 "'remark\\x00pass\\x00function\\x00key\\x00value\\x00path\\x00'\n"
253 " <External File codeid=4 abbrevid=6/> blob data = "
254 "'" EXTERNALFILETESTPATH"'\n"
255 "</Meta>\n");
256}
257
258TEST(BitstreamRemarkSerializer, SeparateRemarkFileAll) {
259 remarks::Remark R;
260 R.RemarkType = remarks::Type::Missed;
261 R.PassName = "pass";
262 R.RemarkName = "remark";
263 R.FunctionName = "function";
264 R.Loc.emplace();
265 R.Loc->SourceFilePath = "path";
266 R.Loc->SourceLine = 99;
267 R.Loc->SourceColumn = 55;
268 R.Hotness.emplace(args: 999999999);
269 R.Args.emplace_back();
270 R.Args.back().Key = "key";
271 R.Args.back().Val = "value";
272 R.Args.back().Loc.emplace();
273 R.Args.back().Loc->SourceFilePath = "argpath";
274 R.Args.back().Loc->SourceLine = 11;
275 R.Args.back().Loc->SourceColumn = 66;
276 check(R,
277 ExpectedR: "<BLOCKINFO_BLOCK/>\n"
278 "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
279 " <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n"
280 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"
281 "</Meta>\n"
282 "<Remark BlockID=9 NumWords=8 BlockCodeSize=4>\n"
283 " <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n"
284 " <Remark debug location codeid=6 abbrevid=5 op0=3 op1=99 op2=55/>\n"
285 " <Remark hotness codeid=7 abbrevid=6 op0=999999999/>\n"
286 " <Argument with debug location codeid=8 abbrevid=7 op0=4 op1=5 op2=6 "
287 "op3=11 op4=66/>\n"
288 "</Remark>\n",
289 ExpectedMeta: "<BLOCKINFO_BLOCK/>\n"
290 "<Meta BlockID=8 NumWords=19 BlockCodeSize=3>\n"
291 " <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n"
292 " <String table codeid=3 abbrevid=5/> blob data = "
293 "'remark\\x00pass\\x00function\\x00path\\x00key\\x00value\\x00argpa"
294 "th\\x00'\n <External File codeid=4 abbrevid=6/> blob data = "
295 "'" EXTERNALFILETESTPATH"'\n"
296 "</Meta>\n");
297}
298
299TEST(BitstreamRemarkSerializer, Standalone) {
300 // Pre-populate the string table.
301 remarks::StringTable StrTab;
302 StrTab.add(Str: "pass");
303 StrTab.add(Str: "remark");
304 StrTab.add(Str: "function");
305 StrTab.add(Str: "path");
306 StrTab.add(Str: "key");
307 StrTab.add(Str: "value");
308 StrTab.add(Str: "argpath");
309 remarks::Remark R;
310 R.RemarkType = remarks::Type::Missed;
311 R.PassName = "pass";
312 R.RemarkName = "remark";
313 R.FunctionName = "function";
314 R.Loc.emplace();
315 R.Loc->SourceFilePath = "path";
316 R.Loc->SourceLine = 99;
317 R.Loc->SourceColumn = 55;
318 R.Hotness.emplace(args: 999999999);
319 R.Args.emplace_back();
320 R.Args.back().Key = "key";
321 R.Args.back().Val = "value";
322 R.Args.back().Loc.emplace();
323 R.Args.back().Loc->SourceFilePath = "argpath";
324 R.Args.back().Loc->SourceLine = 11;
325 R.Args.back().Loc->SourceColumn = 66;
326 checkStandalone(
327 R,
328 ExpectedR: "<BLOCKINFO_BLOCK/>\n"
329 "<Meta BlockID=8 NumWords=15 BlockCodeSize=3>\n"
330 " <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
331 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"
332 " <String table codeid=3 abbrevid=6/> blob data = "
333 "'pass\\x00remark\\x00function\\x00path\\x00key\\x00value\\x00argpath\\x0"
334 "0'\n"
335 "</Meta>\n"
336 "<Remark BlockID=9 NumWords=8 BlockCodeSize=4>\n"
337 " <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
338 " <Remark debug location codeid=6 abbrevid=5 op0=3 op1=99 op2=55/>\n"
339 " <Remark hotness codeid=7 abbrevid=6 op0=999999999/>\n"
340 " <Argument with debug location codeid=8 abbrevid=7 op0=4 op1=5 op2=6 "
341 "op3=11 op4=66/>\n"
342 "</Remark>\n",
343 StrTab: std::move(StrTab));
344}
345

source code of llvm/unittests/Remarks/BitstreamRemarksSerializerTest.cpp