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