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