xref: /llvm-project/llvm/unittests/Remarks/RemarksLinkingTest.cpp (revision e1596d7d9be1659730403b95efb94dad13c8495a)
1 //===- unittest/Support/RemarksLinkingTest.cpp - Linking tests ------------===//
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/RemarkLinker.h"
11 #include "llvm/Remarks/RemarkSerializer.h"
12 #include "llvm/Support/raw_ostream.h"
13 #include "gtest/gtest.h"
14 #include <string>
15 
16 using namespace llvm;
17 
serializeAndCheck(remarks::RemarkLinker & RL,remarks::Format OutputFormat,StringRef ExpectedOutput)18 static void serializeAndCheck(remarks::RemarkLinker &RL,
19                               remarks::Format OutputFormat,
20                               StringRef ExpectedOutput) {
21   // 1. Create a serializer.
22   // 2. Serialize all the remarks from the linker.
23   // 3. Check that it matches the output.
24   std::string Buf;
25   raw_string_ostream OS(Buf);
26   Error E = RL.serialize(OS, OutputFormat);
27   EXPECT_FALSE(static_cast<bool>(E));
28 
29   // For bitstream, run it through the analyzer.
30   if (OutputFormat == remarks::Format::Bitstream) {
31     std::string AnalyzeBuf;
32     raw_string_ostream AnalyzeOS(AnalyzeBuf);
33     BCDumpOptions O(AnalyzeOS);
34     O.ShowBinaryBlobs = true;
35     BitcodeAnalyzer BA(OS.str());
36     EXPECT_FALSE(BA.analyze(O)); // Expect no errors.
37     EXPECT_EQ(AnalyzeOS.str(), ExpectedOutput);
38   } else {
39     EXPECT_EQ(OS.str(), ExpectedOutput);
40   }
41 }
42 
check(remarks::Format InputFormat,StringRef Input,remarks::Format OutputFormat,StringRef ExpectedOutput,std::optional<bool> KeepAllRemarks={})43 static void check(remarks::Format InputFormat, StringRef Input,
44                   remarks::Format OutputFormat, StringRef ExpectedOutput,
45                   std::optional<bool> KeepAllRemarks = {}) {
46   remarks::RemarkLinker RL;
47   if (KeepAllRemarks)
48     RL.setKeepAllRemarks(*KeepAllRemarks);
49   EXPECT_FALSE(RL.link(Input, InputFormat));
50   serializeAndCheck(RL, OutputFormat, ExpectedOutput);
51 }
52 
check(remarks::Format InputFormat,StringRef Input,remarks::Format InputFormat2,StringRef Input2,remarks::Format OutputFormat,StringRef ExpectedOutput)53 static void check(remarks::Format InputFormat, StringRef Input,
54                   remarks::Format InputFormat2, StringRef Input2,
55                   remarks::Format OutputFormat, StringRef ExpectedOutput) {
56   remarks::RemarkLinker RL;
57   EXPECT_FALSE(RL.link(Input, InputFormat));
58   EXPECT_FALSE(RL.link(Input2, InputFormat2));
59   serializeAndCheck(RL, OutputFormat, ExpectedOutput);
60 }
61 
TEST(Remarks,LinkingGoodYAML)62 TEST(Remarks, LinkingGoodYAML) {
63   // One YAML remark.
64   check(remarks::Format::YAML,
65         "--- !Missed\n"
66         "Pass:            inline\n"
67         "Name:            NoDefinition\n"
68         "DebugLoc:        { File: file.c, Line: 3, Column: 12 }\n"
69         "Function:        foo\n"
70         "...\n",
71         remarks::Format::YAML,
72         "--- !Missed\n"
73         "Pass:            inline\n"
74         "Name:            NoDefinition\n"
75         "DebugLoc:        { File: file.c, Line: 3, Column: 12 }\n"
76         "Function:        foo\n"
77         "...\n");
78 
79   // Check that we don't keep remarks without debug locations, unless
80   // KeepAllRemarks is set.
81   check(remarks::Format::YAML,
82         "--- !Missed\n"
83         "Pass:            inline\n"
84         "Name:            NoDefinition\n"
85         "Function:        foo\n"
86         "...\n",
87         remarks::Format::YAML, "",
88         /*KeepAllRemarks=*/false);
89   check(remarks::Format::YAML,
90         "--- !Missed\n"
91         "Pass:            inline\n"
92         "Name:            NoDefinition\n"
93         "Function:        foo\n"
94         "...\n",
95         remarks::Format::YAML,
96         "--- !Missed\n"
97         "Pass:            inline\n"
98         "Name:            NoDefinition\n"
99         "Function:        foo\n"
100         "...\n");
101 
102   // Check that we deduplicate remarks.
103   check(remarks::Format::YAML,
104         "--- !Missed\n"
105         "Pass:            inline\n"
106         "Name:            NoDefinition\n"
107         "DebugLoc:        { File: file.c, Line: 3, Column: 12 }\n"
108         "Function:        foo\n"
109         "...\n"
110         "--- !Missed\n"
111         "Pass:            inline\n"
112         "Name:            NoDefinition\n"
113         "DebugLoc:        { File: file.c, Line: 3, Column: 12 }\n"
114         "Function:        foo\n"
115         "...\n",
116         remarks::Format::YAML,
117         "--- !Missed\n"
118         "Pass:            inline\n"
119         "Name:            NoDefinition\n"
120         "DebugLoc:        { File: file.c, Line: 3, Column: 12 }\n"
121         "Function:        foo\n"
122         "...\n");
123 }
124 
TEST(Remarks,LinkingGoodBitstream)125 TEST(Remarks, LinkingGoodBitstream) {
126   // One YAML remark.
127   check(remarks::Format::YAML,
128         "--- !Missed\n"
129         "Pass:            inline\n"
130         "Name:            NoDefinition\n"
131         "DebugLoc:        { File: file.c, Line: 3, Column: 12 }\n"
132         "Function:        foo\n"
133         "...\n",
134         remarks::Format::Bitstream,
135         "<BLOCKINFO_BLOCK/>\n"
136         "<Meta BlockID=8 NumWords=12 BlockCodeSize=3>\n"
137         "  <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
138         "  <Remark version codeid=2 abbrevid=5 op0=0/>\n"
139         "  <String table codeid=3 abbrevid=6/> blob data = "
140         "'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00'\n"
141         "</Meta>\n"
142         "<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
143         "  <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
144         "  <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"
145         "</Remark>\n");
146 
147   // Check that we keep remarks without debug info.
148   check(remarks::Format::YAML,
149         "--- !Missed\n"
150         "Pass:            inline\n"
151         "Name:            NoDefinition\n"
152         "Function:        foo\n"
153         "...\n",
154         remarks::Format::Bitstream,
155         "<BLOCKINFO_BLOCK/>\n"
156         "<Meta BlockID=8 NumWords=10 BlockCodeSize=3>\n"
157         "  <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
158         "  <Remark version codeid=2 abbrevid=5 op0=0/>\n"
159         "  <String table codeid=3 abbrevid=6/> blob data = "
160         "'inline\\x00NoDefinition\\x00foo\\x00'\n"
161         "</Meta>\n"
162         "<Remark BlockID=9 NumWords=1 BlockCodeSize=4>\n"
163         "  <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
164         "</Remark>\n");
165 
166   // Check that we deduplicate remarks.
167   check(remarks::Format::YAML,
168         "--- !Missed\n"
169         "Pass:            inline\n"
170         "Name:            NoDefinition\n"
171         "DebugLoc:        { File: file.c, Line: 3, Column: 12 }\n"
172         "Function:        foo\n"
173         "...\n"
174         "--- !Missed\n"
175         "Pass:            inline\n"
176         "Name:            NoDefinition\n"
177         "DebugLoc:        { File: file.c, Line: 3, Column: 12 }\n"
178         "Function:        foo\n"
179         "...\n",
180         remarks::Format::Bitstream,
181         "<BLOCKINFO_BLOCK/>\n"
182         "<Meta BlockID=8 NumWords=12 BlockCodeSize=3>\n"
183         "  <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
184         "  <Remark version codeid=2 abbrevid=5 op0=0/>\n"
185         "  <String table codeid=3 abbrevid=6/> blob data = "
186         "'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00'\n"
187         "</Meta>\n"
188         "<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
189         "  <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
190         "  <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"
191         "</Remark>\n");
192 }
193 
TEST(Remarks,LinkingGoodStrTab)194 TEST(Remarks, LinkingGoodStrTab) {
195   // Check that remarks from different entries use the same strtab.
196   check(remarks::Format::YAML,
197         "--- !Missed\n"
198         "Pass:            inline\n"
199         "Name:            NoDefinition\n"
200         "DebugLoc:        { File: file.c, Line: 3, Column: 12 }\n"
201         "Function:        foo\n"
202         "...\n",
203         remarks::Format::YAML,
204         "--- !Passed\n"
205         "Pass:            inline\n"
206         "Name:            Ok\n"
207         "DebugLoc:        { File: file.c, Line: 3, Column: 12 }\n"
208         "Function:        foo\n"
209         "...\n",
210         remarks::Format::YAMLStrTab,
211         StringRef("REMARKS\0\0\0\0\0\0\0\0\0\x22\0\0\0\0\0\0\0"
212                   "inline\0NoDefinition\0foo\0file.c\0Ok\0"
213                   "--- !Passed\n"
214                   "Pass:            0\n"
215                   "Name:            4\n"
216                   "DebugLoc:        { File: 3, Line: 3, Column: 12 }\n"
217                   "Function:        2\n"
218                   "...\n"
219                   "--- !Missed\n"
220                   "Pass:            0\n"
221                   "Name:            1\n"
222                   "DebugLoc:        { File: 3, Line: 3, Column: 12 }\n"
223                   "Function:        2\n"
224                   "...\n",
225                   304));
226 }
227 
228 // Check that we propagate parsing errors.
TEST(Remarks,LinkingError)229 TEST(Remarks, LinkingError) {
230   remarks::RemarkLinker RL;
231   {
232     Error E = RL.link("badyaml", remarks::Format::YAML);
233     EXPECT_TRUE(static_cast<bool>(E));
234     EXPECT_EQ(toString(std::move(E)),
235               "YAML:1:1: error: document root is not of mapping type.\n"
236               "\n"
237               "badyaml\n"
238               "^~~~~~~\n"
239               "\n");
240   }
241 
242   {
243     // Check that the prepend path is propagated and fails with the full path.
244     RL.setExternalFilePrependPath("/baddir/");
245     Error E = RL.link(
246         StringRef("REMARKS\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0badfile.opt.yaml",
247                   40),
248         remarks::Format::YAMLStrTab);
249     EXPECT_TRUE(static_cast<bool>(E));
250     std::string ErrorMessage = toString(std::move(E));
251     EXPECT_EQ(StringRef(ErrorMessage).lower(),
252               StringRef("'/baddir/badfile.opt.yaml': No such file or directory")
253                   .lower());
254   }
255 }
256