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 | |
25 | using namespace llvm; |
26 | |
27 | static 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 | |
37 | static void (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 | |
69 | static void (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 | |
76 | static void |
77 | checkStandalone(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 | |
83 | TEST(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 | |
108 | TEST(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 | |
138 | TEST(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 | |
168 | TEST(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 | |
195 | TEST(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 | |
224 | TEST(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 | |
258 | TEST(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 | |
299 | TEST(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 | |