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