//===- 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 // 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 ExpectedMeta, Optional StrTab) { // Emit the remark. std::string InputBuf; raw_string_ostream InputOS(InputBuf); Expected> 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 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 MetaSerializer = Serializer->metaSerializer(MetaOS, StringRef(EXTERNALFILETESTPATH)); MetaSerializer->emit(); checkAnalyze(MetaOS.str(), *ExpectedMeta); } } static void check(const remarks::Remark &R, StringRef ExpectedR, StringRef ExpectedMeta, Optional StrTab = None) { return check(remarks::SerializerMode::Separate, R, ExpectedR, ExpectedMeta, std::move(StrTab)); } static void checkStandalone(const remarks::Remark &R, StringRef ExpectedR, Optional 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, "\n" "\n" " \n" " \n" "\n" "\n" " \n" "\n", "\n" "\n" " \n" " blob data = " "'remark\\x00pass\\x00function\\x00'\n" " blob data = " "'" EXTERNALFILETESTPATH"'\n" "\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, "\n" "\n" " \n" " \n" "\n" "\n" " \n" "\n", "\n" "\n" " \n" " blob data = " "'function\\x00pass\\x00remark\\x00'\n" " blob data = " "'" EXTERNALFILETESTPATH"'\n" "\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, "\n" "\n" " \n" " \n" "\n" "\n" " \n" " \n" "\n", "\n" "\n" " \n" " blob data = " "'remark\\x00pass\\x00function\\x00path\\x00'\n" " blob data = " "'" EXTERNALFILETESTPATH"'\n" "\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, "\n" "\n" " \n" " \n" "\n" "\n" " \n" " \n" "\n", "\n" "\n" " \n" " blob data = " "'remark\\x00pass\\x00function\\x00'\n" " blob data = " "'" EXTERNALFILETESTPATH"'\n" "\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, "\n" "\n" " \n" " \n" "\n" "\n" " \n" " \n" "\n", "\n" "\n" " \n" " blob data = " "'remark\\x00pass\\x00function\\x00key\\x00value\\x00'\n" " blob data = " "'" EXTERNALFILETESTPATH"'\n" "\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, "\n" "\n" " \n" " \n" "\n" "\n" " \n" " \n" "\n", "\n" "\n" " \n" " blob data = " "'remark\\x00pass\\x00function\\x00key\\x00value\\x00path\\x00'\n" " blob data = " "'" EXTERNALFILETESTPATH"'\n" "\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, "\n" "\n" " \n" " \n" "\n" "\n" " \n" " \n" " \n" " \n" "\n", "\n" "\n" " \n" " blob data = " "'remark\\x00pass\\x00function\\x00path\\x00key\\x00value\\x00argpa" "th\\x00'\n blob data = " "'" EXTERNALFILETESTPATH"'\n" "\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, "\n" "\n" " \n" " \n" " blob data = " "'pass\\x00remark\\x00function\\x00path\\x00key\\x00value\\x00argpath\\x0" "0'\n" "\n" "\n" " \n" " \n" " \n" " \n" "\n", std::move(StrTab)); }