150
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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 }
|