| //===- unittest/Support/BitstreamRemarksSerializerTest.cpp ----------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/Bitcode/BitcodeAnalyzer.h" |
| #include "llvm/Remarks/BitstreamRemarkSerializer.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include "gtest/gtest.h" |
| #include <string> |
| |
| // We need to supprt Windows paths as well. In order to have paths with the same |
| // length, use a different path according to the platform. |
| #ifdef _WIN32 |
| #define EXTERNALFILETESTPATH "C:/externalfi" |
| #else |
| #define EXTERNALFILETESTPATH "/externalfile" |
| #endif |
| |
| using namespace llvm; |
| |
| static void checkAnalyze(StringRef Input, StringRef Expected) { |
| std::string OutputBuf; |
| raw_string_ostream OutputOS(OutputBuf); |
| BCDumpOptions O(OutputOS); |
| O.ShowBinaryBlobs = true; |
| BitcodeAnalyzer BA(Input); |
| EXPECT_FALSE(BA.analyze(O)); // Expect no errors. |
| EXPECT_EQ(OutputOS.str(), Expected); |
| } |
| |
| static void check(remarks::SerializerMode Mode, const remarks::Remark &R, |
| StringRef ExpectedR, Optional<StringRef> ExpectedMeta, |
| Optional<remarks::StringTable> StrTab) { |
| // Emit the remark. |
| std::string InputBuf; |
| raw_string_ostream InputOS(InputBuf); |
| Expected<std::unique_ptr<remarks::RemarkSerializer>> MaybeSerializer = [&] { |
| if (StrTab) |
| return createRemarkSerializer(remarks::Format::Bitstream, Mode, InputOS, |
| std::move(*StrTab)); |
| else |
| return createRemarkSerializer(remarks::Format::Bitstream, Mode, InputOS); |
| }(); |
| EXPECT_FALSE(errorToBool(MaybeSerializer.takeError())); |
| std::unique_ptr<remarks::RemarkSerializer> Serializer = |
| std::move(*MaybeSerializer); |
| Serializer->emit(R); |
| |
| // Analyze the serialized remark. |
| checkAnalyze(InputOS.str(), ExpectedR); |
| |
| // Analyze the serialized metadata if it's not in standalone mode. |
| if (ExpectedMeta) { |
| std::string MetaBuf; |
| raw_string_ostream MetaOS(MetaBuf); |
| std::unique_ptr<remarks::MetaSerializer> MetaSerializer = |
| Serializer->metaSerializer(MetaOS, StringRef(EXTERNALFILETESTPATH)); |
| MetaSerializer->emit(); |
| checkAnalyze(MetaOS.str(), *ExpectedMeta); |
| } |
| } |
| |
| static void check(const remarks::Remark &R, StringRef ExpectedR, |
| StringRef ExpectedMeta, |
| Optional<remarks::StringTable> StrTab = None) { |
| return check(remarks::SerializerMode::Separate, R, ExpectedR, ExpectedMeta, |
| std::move(StrTab)); |
| } |
| |
| static void checkStandalone(const remarks::Remark &R, StringRef ExpectedR, |
| Optional<remarks::StringTable> StrTab = None) { |
| return check(remarks::SerializerMode::Standalone, R, ExpectedR, |
| /*ExpectedMeta=*/None, std::move(StrTab)); |
| } |
| |
| TEST(BitstreamRemarkSerializer, SeparateRemarkFileNoOptionals) { |
| remarks::Remark R; |
| R.RemarkType = remarks::Type::Missed; |
| R.PassName = "pass"; |
| R.RemarkName = "remark"; |
| R.FunctionName = "function"; |
| check(R, |
| "<BLOCKINFO_BLOCK/>\n" |
| "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n" |
| " <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n" |
| " <Remark version codeid=2 abbrevid=5 op0=0/>\n" |
| "</Meta>\n" |
| "<Remark BlockID=9 NumWords=1 BlockCodeSize=4>\n" |
| " <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n" |
| "</Remark>\n", |
| "<BLOCKINFO_BLOCK/>\n" |
| "<Meta BlockID=8 NumWords=14 BlockCodeSize=3>\n" |
| " <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n" |
| " <String table codeid=3 abbrevid=5/> blob data = " |
| "'remark\\x00pass\\x00function\\x00'\n" |
| " <External File codeid=4 abbrevid=6/> blob data = " |
| "'" EXTERNALFILETESTPATH"'\n" |
| "</Meta>\n"); |
| } |
| |
| TEST(BitstreamRemarkSerializer, SeparateRemarkFileNoOptionalsSeparateStrTab) { |
| remarks::StringTable StrTab; |
| StrTab.add("function"); |
| StrTab.add("pass"); |
| StrTab.add("remark"); |
| remarks::Remark R; |
| R.RemarkType = remarks::Type::Missed; |
| R.PassName = "pass"; |
| R.RemarkName = "remark"; |
| R.FunctionName = "function"; |
| check(R, |
| "<BLOCKINFO_BLOCK/>\n" |
| "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n" |
| " <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n" |
| " <Remark version codeid=2 abbrevid=5 op0=0/>\n" |
| "</Meta>\n" |
| "<Remark BlockID=9 NumWords=1 BlockCodeSize=4>\n" |
| " <Remark header codeid=5 abbrevid=4 op0=2 op1=2 op2=1 op3=0/>\n" |
| "</Remark>\n", |
| "<BLOCKINFO_BLOCK/>\n" |
| "<Meta BlockID=8 NumWords=14 BlockCodeSize=3>\n" |
| " <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n" |
| " <String table codeid=3 abbrevid=5/> blob data = " |
| "'function\\x00pass\\x00remark\\x00'\n" |
| " <External File codeid=4 abbrevid=6/> blob data = " |
| "'" EXTERNALFILETESTPATH"'\n" |
| "</Meta>\n", |
| std::move(StrTab)); |
| } |
| |
| TEST(BitstreamRemarkSerializer, SeparateRemarkFileDebugLoc) { |
| remarks::Remark R; |
| R.RemarkType = remarks::Type::Missed; |
| R.PassName = "pass"; |
| R.RemarkName = "remark"; |
| R.FunctionName = "function"; |
| R.Loc.emplace(); |
| R.Loc->SourceFilePath = "path"; |
| R.Loc->SourceLine = 99; |
| R.Loc->SourceColumn = 55; |
| check(R, |
| "<BLOCKINFO_BLOCK/>\n" |
| "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n" |
| " <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n" |
| " <Remark version codeid=2 abbrevid=5 op0=0/>\n" |
| "</Meta>\n" |
| "<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n" |
| " <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n" |
| " <Remark debug location codeid=6 abbrevid=5 op0=3 op1=99 op2=55/>\n" |
| "</Remark>\n", |
| "<BLOCKINFO_BLOCK/>\n" |
| "<Meta BlockID=8 NumWords=15 BlockCodeSize=3>\n" |
| " <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n" |
| " <String table codeid=3 abbrevid=5/> blob data = " |
| "'remark\\x00pass\\x00function\\x00path\\x00'\n" |
| " <External File codeid=4 abbrevid=6/> blob data = " |
| "'" EXTERNALFILETESTPATH"'\n" |
| "</Meta>\n"); |
| } |
| |
| TEST(BitstreamRemarkSerializer, SeparateRemarkFileHotness) { |
| remarks::Remark R; |
| R.RemarkType = remarks::Type::Missed; |
| R.PassName = "pass"; |
| R.RemarkName = "remark"; |
| R.FunctionName = "function"; |
| R.Hotness.emplace(999999999); |
| check(R, |
| "<BLOCKINFO_BLOCK/>\n" |
| "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n" |
| " <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n" |
| " <Remark version codeid=2 abbrevid=5 op0=0/>\n" |
| "</Meta>\n" |
| "<Remark BlockID=9 NumWords=3 BlockCodeSize=4>\n" |
| " <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n" |
| " <Remark hotness codeid=7 abbrevid=6 op0=999999999/>\n" |
| "</Remark>\n", |
| "<BLOCKINFO_BLOCK/>\n" |
| "<Meta BlockID=8 NumWords=14 BlockCodeSize=3>\n" |
| " <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n" |
| " <String table codeid=3 abbrevid=5/> blob data = " |
| "'remark\\x00pass\\x00function\\x00'\n" |
| " <External File codeid=4 abbrevid=6/> blob data = " |
| "'" EXTERNALFILETESTPATH"'\n" |
| "</Meta>\n"); |
| } |
| |
| TEST(BitstreamRemarkSerializer, SeparateRemarkFileArgNoDebugLoc) { |
| remarks::Remark R; |
| R.RemarkType = remarks::Type::Missed; |
| R.PassName = "pass"; |
| R.RemarkName = "remark"; |
| R.FunctionName = "function"; |
| R.Args.emplace_back(); |
| R.Args.back().Key = "key"; |
| R.Args.back().Val = "value"; |
| check(R, |
| "<BLOCKINFO_BLOCK/>\n" |
| "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n" |
| " <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n" |
| " <Remark version codeid=2 abbrevid=5 op0=0/>\n" |
| "</Meta>\n" |
| "<Remark BlockID=9 NumWords=2 BlockCodeSize=4>\n" |
| " <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n" |
| " <Argument codeid=9 abbrevid=8 op0=3 op1=4/>\n" |
| "</Remark>\n", |
| "<BLOCKINFO_BLOCK/>\n" |
| "<Meta BlockID=8 NumWords=16 BlockCodeSize=3>\n" |
| " <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n" |
| " <String table codeid=3 abbrevid=5/> blob data = " |
| "'remark\\x00pass\\x00function\\x00key\\x00value\\x00'\n" |
| " <External File codeid=4 abbrevid=6/> blob data = " |
| "'" EXTERNALFILETESTPATH"'\n" |
| "</Meta>\n"); |
| } |
| |
| TEST(BitstreamRemarkSerializer, SeparateRemarkFileArgDebugLoc) { |
| remarks::Remark R; |
| R.RemarkType = remarks::Type::Missed; |
| R.PassName = "pass"; |
| R.RemarkName = "remark"; |
| R.FunctionName = "function"; |
| R.Args.emplace_back(); |
| R.Args.back().Key = "key"; |
| R.Args.back().Val = "value"; |
| R.Args.back().Loc.emplace(); |
| R.Args.back().Loc->SourceFilePath = "path"; |
| R.Args.back().Loc->SourceLine = 99; |
| R.Args.back().Loc->SourceColumn = 55; |
| check(R, |
| "<BLOCKINFO_BLOCK/>\n" |
| "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n" |
| " <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n" |
| " <Remark version codeid=2 abbrevid=5 op0=0/>\n" |
| "</Meta>\n" |
| "<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n" |
| " <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n" |
| " <Argument with debug location codeid=8 abbrevid=7 op0=3 op1=4 op2=5 " |
| "op3=99 op4=55/>\n" |
| "</Remark>\n", |
| "<BLOCKINFO_BLOCK/>\n" |
| "<Meta BlockID=8 NumWords=17 BlockCodeSize=3>\n" |
| " <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n" |
| " <String table codeid=3 abbrevid=5/> blob data = " |
| "'remark\\x00pass\\x00function\\x00key\\x00value\\x00path\\x00'\n" |
| " <External File codeid=4 abbrevid=6/> blob data = " |
| "'" EXTERNALFILETESTPATH"'\n" |
| "</Meta>\n"); |
| } |
| |
| TEST(BitstreamRemarkSerializer, SeparateRemarkFileAll) { |
| remarks::Remark R; |
| R.RemarkType = remarks::Type::Missed; |
| R.PassName = "pass"; |
| R.RemarkName = "remark"; |
| R.FunctionName = "function"; |
| R.Loc.emplace(); |
| R.Loc->SourceFilePath = "path"; |
| R.Loc->SourceLine = 99; |
| R.Loc->SourceColumn = 55; |
| R.Hotness.emplace(999999999); |
| R.Args.emplace_back(); |
| R.Args.back().Key = "key"; |
| R.Args.back().Val = "value"; |
| R.Args.back().Loc.emplace(); |
| R.Args.back().Loc->SourceFilePath = "argpath"; |
| R.Args.back().Loc->SourceLine = 11; |
| R.Args.back().Loc->SourceColumn = 66; |
| check(R, |
| "<BLOCKINFO_BLOCK/>\n" |
| "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n" |
| " <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n" |
| " <Remark version codeid=2 abbrevid=5 op0=0/>\n" |
| "</Meta>\n" |
| "<Remark BlockID=9 NumWords=8 BlockCodeSize=4>\n" |
| " <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n" |
| " <Remark debug location codeid=6 abbrevid=5 op0=3 op1=99 op2=55/>\n" |
| " <Remark hotness codeid=7 abbrevid=6 op0=999999999/>\n" |
| " <Argument with debug location codeid=8 abbrevid=7 op0=4 op1=5 op2=6 " |
| "op3=11 op4=66/>\n" |
| "</Remark>\n", |
| "<BLOCKINFO_BLOCK/>\n" |
| "<Meta BlockID=8 NumWords=19 BlockCodeSize=3>\n" |
| " <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n" |
| " <String table codeid=3 abbrevid=5/> blob data = " |
| "'remark\\x00pass\\x00function\\x00path\\x00key\\x00value\\x00argpa" |
| "th\\x00'\n <External File codeid=4 abbrevid=6/> blob data = " |
| "'" EXTERNALFILETESTPATH"'\n" |
| "</Meta>\n"); |
| } |
| |
| TEST(BitstreamRemarkSerializer, Standalone) { |
| // Pre-populate the string table. |
| remarks::StringTable StrTab; |
| StrTab.add("pass"); |
| StrTab.add("remark"); |
| StrTab.add("function"); |
| StrTab.add("path"); |
| StrTab.add("key"); |
| StrTab.add("value"); |
| StrTab.add("argpath"); |
| remarks::Remark R; |
| R.RemarkType = remarks::Type::Missed; |
| R.PassName = "pass"; |
| R.RemarkName = "remark"; |
| R.FunctionName = "function"; |
| R.Loc.emplace(); |
| R.Loc->SourceFilePath = "path"; |
| R.Loc->SourceLine = 99; |
| R.Loc->SourceColumn = 55; |
| R.Hotness.emplace(999999999); |
| R.Args.emplace_back(); |
| R.Args.back().Key = "key"; |
| R.Args.back().Val = "value"; |
| R.Args.back().Loc.emplace(); |
| R.Args.back().Loc->SourceFilePath = "argpath"; |
| R.Args.back().Loc->SourceLine = 11; |
| R.Args.back().Loc->SourceColumn = 66; |
| checkStandalone( |
| R, |
| "<BLOCKINFO_BLOCK/>\n" |
| "<Meta BlockID=8 NumWords=15 BlockCodeSize=3>\n" |
| " <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n" |
| " <Remark version codeid=2 abbrevid=5 op0=0/>\n" |
| " <String table codeid=3 abbrevid=6/> blob data = " |
| "'pass\\x00remark\\x00function\\x00path\\x00key\\x00value\\x00argpath\\x0" |
| "0'\n" |
| "</Meta>\n" |
| "<Remark BlockID=9 NumWords=8 BlockCodeSize=4>\n" |
| " <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n" |
| " <Remark debug location codeid=6 abbrevid=5 op0=3 op1=99 op2=55/>\n" |
| " <Remark hotness codeid=7 abbrevid=6 op0=999999999/>\n" |
| " <Argument with debug location codeid=8 abbrevid=7 op0=4 op1=5 op2=6 " |
| "op3=11 op4=66/>\n" |
| "</Remark>\n", |
| std::move(StrTab)); |
| } |