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 } 220