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)43 static void check(remarks::Format InputFormat, StringRef Input,
44 remarks::Format OutputFormat, StringRef ExpectedOutput) {
45 remarks::RemarkLinker RL;
46 EXPECT_FALSE(RL.link(Input, InputFormat));
47 serializeAndCheck(RL, OutputFormat, ExpectedOutput);
48 }
49
check(remarks::Format InputFormat,StringRef Input,remarks::Format InputFormat2,StringRef Input2,remarks::Format OutputFormat,StringRef ExpectedOutput)50 static void check(remarks::Format InputFormat, StringRef Input,
51 remarks::Format InputFormat2, StringRef Input2,
52 remarks::Format OutputFormat, StringRef ExpectedOutput) {
53 remarks::RemarkLinker RL;
54 EXPECT_FALSE(RL.link(Input, InputFormat));
55 EXPECT_FALSE(RL.link(Input2, InputFormat2));
56 serializeAndCheck(RL, OutputFormat, ExpectedOutput);
57 }
58
TEST(Remarks,LinkingGoodYAML)59 TEST(Remarks, LinkingGoodYAML) {
60 // One YAML remark.
61 check(remarks::Format::YAML,
62 "--- !Missed\n"
63 "Pass: inline\n"
64 "Name: NoDefinition\n"
65 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
66 "Function: foo\n"
67 "...\n",
68 remarks::Format::YAML,
69 "--- !Missed\n"
70 "Pass: inline\n"
71 "Name: NoDefinition\n"
72 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
73 "Function: foo\n"
74 "...\n");
75
76 // Check that we don't keep remarks without debug locations.
77 check(remarks::Format::YAML,
78 "--- !Missed\n"
79 "Pass: inline\n"
80 "Name: NoDefinition\n"
81 "Function: foo\n"
82 "...\n",
83 remarks::Format::YAML, "");
84
85 // Check that we deduplicate remarks.
86 check(remarks::Format::YAML,
87 "--- !Missed\n"
88 "Pass: inline\n"
89 "Name: NoDefinition\n"
90 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
91 "Function: foo\n"
92 "...\n"
93 "--- !Missed\n"
94 "Pass: inline\n"
95 "Name: NoDefinition\n"
96 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
97 "Function: foo\n"
98 "...\n",
99 remarks::Format::YAML,
100 "--- !Missed\n"
101 "Pass: inline\n"
102 "Name: NoDefinition\n"
103 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
104 "Function: foo\n"
105 "...\n");
106 }
107
TEST(Remarks,LinkingGoodBitstream)108 TEST(Remarks, LinkingGoodBitstream) {
109 // One YAML remark.
110 check(remarks::Format::YAML,
111 "--- !Missed\n"
112 "Pass: inline\n"
113 "Name: NoDefinition\n"
114 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
115 "Function: foo\n"
116 "...\n",
117 remarks::Format::Bitstream,
118 "<BLOCKINFO_BLOCK/>\n"
119 "<Meta BlockID=8 NumWords=12 BlockCodeSize=3>\n"
120 " <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
121 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"
122 " <String table codeid=3 abbrevid=6/> blob data = "
123 "'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00'\n"
124 "</Meta>\n"
125 "<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
126 " <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
127 " <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"
128 "</Remark>\n");
129
130 // Check that we deduplicate remarks.
131 check(remarks::Format::YAML,
132 "--- !Missed\n"
133 "Pass: inline\n"
134 "Name: NoDefinition\n"
135 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
136 "Function: foo\n"
137 "...\n"
138 "--- !Missed\n"
139 "Pass: inline\n"
140 "Name: NoDefinition\n"
141 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
142 "Function: foo\n"
143 "...\n",
144 remarks::Format::Bitstream,
145 "<BLOCKINFO_BLOCK/>\n"
146 "<Meta BlockID=8 NumWords=12 BlockCodeSize=3>\n"
147 " <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
148 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"
149 " <String table codeid=3 abbrevid=6/> blob data = "
150 "'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00'\n"
151 "</Meta>\n"
152 "<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
153 " <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
154 " <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"
155 "</Remark>\n");
156 }
157
TEST(Remarks,LinkingGoodStrTab)158 TEST(Remarks, LinkingGoodStrTab) {
159 // Check that remarks from different entries use the same strtab.
160 check(remarks::Format::YAML,
161 "--- !Missed\n"
162 "Pass: inline\n"
163 "Name: NoDefinition\n"
164 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
165 "Function: foo\n"
166 "...\n",
167 remarks::Format::YAML,
168 "--- !Passed\n"
169 "Pass: inline\n"
170 "Name: Ok\n"
171 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
172 "Function: foo\n"
173 "...\n",
174 remarks::Format::YAMLStrTab,
175 StringRef("REMARKS\0\0\0\0\0\0\0\0\0\x22\0\0\0\0\0\0\0"
176 "inline\0NoDefinition\0foo\0file.c\0Ok\0"
177 "--- !Passed\n"
178 "Pass: 0\n"
179 "Name: 4\n"
180 "DebugLoc: { File: 3, Line: 3, Column: 12 }\n"
181 "Function: 2\n"
182 "...\n"
183 "--- !Missed\n"
184 "Pass: 0\n"
185 "Name: 1\n"
186 "DebugLoc: { File: 3, Line: 3, Column: 12 }\n"
187 "Function: 2\n"
188 "...\n",
189 304));
190 }
191
192 // Check that we propagate parsing errors.
TEST(Remarks,LinkingError)193 TEST(Remarks, LinkingError) {
194 remarks::RemarkLinker RL;
195 {
196 Error E = RL.link("badyaml", remarks::Format::YAML);
197 EXPECT_TRUE(static_cast<bool>(E));
198 EXPECT_EQ(toString(std::move(E)),
199 "YAML:1:1: error: document root is not of mapping type.\n"
200 "\n"
201 "badyaml\n"
202 "^~~~~~~\n"
203 "\n");
204 }
205
206 {
207 // Check that the prepend path is propagated and fails with the full path.
208 RL.setExternalFilePrependPath("/baddir/");
209 Error E = RL.link(
210 StringRef("REMARKS\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0badfile.opt.yaml",
211 40),
212 remarks::Format::YAMLStrTab);
213 EXPECT_TRUE(static_cast<bool>(E));
214 std::string ErrorMessage = toString(std::move(E));
215 EXPECT_EQ(StringRef(ErrorMessage).lower(),
216 StringRef("'/baddir/badfile.opt.yaml': No such file or directory")
217 .lower());
218 }
219 }
220