From e14c0c5ae0112e714c7f83a45753116b871fbfaf Mon Sep 17 00:00:00 2001 From: Francis Visoiu Mistrih Date: Fri, 6 Sep 2019 17:22:51 +0000 Subject: [PATCH] [Remarks] Add support for internalizing a remark in a string table In order to keep remarks around, we need to make them tied to a string table. Users then can delete the parser and rely on the string table to keep the memory of the strings alive and deduplicated. llvm-svn: 371233 --- llvm/include/llvm/Remarks/RemarkStringTable.h | 3 ++ llvm/lib/Remarks/RemarkStringTable.cpp | 17 ++++++++++ llvm/unittests/Remarks/RemarksAPITest.cpp | 46 +++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/llvm/include/llvm/Remarks/RemarkStringTable.h b/llvm/include/llvm/Remarks/RemarkStringTable.h index be2596d..80d8276 100644 --- a/llvm/include/llvm/Remarks/RemarkStringTable.h +++ b/llvm/include/llvm/Remarks/RemarkStringTable.h @@ -51,6 +51,9 @@ struct StringTable { /// Add a string to the table. It returns an unique ID of the string. std::pair add(StringRef Str); + /// Modify \p R to use strings from this string table. If the string table + /// does not contain the strings, it adds them. + void internalize(Remark &R); /// Serialize the string table to a stream. It is serialized as a little /// endian uint64 (the size of the table in bytes) followed by a sequence of /// NULL-terminated strings, where the N-th string is the string with the ID N diff --git a/llvm/lib/Remarks/RemarkStringTable.cpp b/llvm/lib/Remarks/RemarkStringTable.cpp index 17aa394..0f8a95a 100644 --- a/llvm/lib/Remarks/RemarkStringTable.cpp +++ b/llvm/lib/Remarks/RemarkStringTable.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Remarks/RemarkStringTable.h" +#include "llvm/Remarks/Remark.h" #include "llvm/Remarks/RemarkParser.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/Error.h" @@ -37,6 +38,22 @@ std::pair StringTable::add(StringRef Str) { return {KV.first->second, KV.first->first()}; } +void StringTable::internalize(Remark &R) { + auto Impl = [&](StringRef &S) { S = add(S).second; }; + Impl(R.PassName); + Impl(R.RemarkName); + Impl(R.FunctionName); + if (R.Loc) + Impl(R.Loc->SourceFilePath); + for (Argument &Arg : R.Args) { + // We need to mutate elements from an ArrayRef here. + Impl(Arg.Key); + Impl(Arg.Val); + if (Arg.Loc) + Impl(Arg.Loc->SourceFilePath); + } +} + void StringTable::serialize(raw_ostream &OS) const { // Emit the sequence of strings. for (StringRef Str : serialize()) { diff --git a/llvm/unittests/Remarks/RemarksAPITest.cpp b/llvm/unittests/Remarks/RemarksAPITest.cpp index 23a45e9..19fa90f 100644 --- a/llvm/unittests/Remarks/RemarksAPITest.cpp +++ b/llvm/unittests/Remarks/RemarksAPITest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Remarks/Remark.h" +#include "llvm/Remarks/RemarkStringTable.h" #include "gtest/gtest.h" using namespace llvm; @@ -75,3 +76,48 @@ TEST(RemarksAPI, ArgsAsMsg) { EXPECT_EQ(R.getArgsAsMsg(), "can not do this because of that."); } + +TEST(RemarksAPI, StringTableInternalize) { + remarks::StringTable StrTab; + + // Empty table. + EXPECT_EQ(StrTab.SerializedSize, 0UL); + + remarks::Remark R; + R.RemarkType = remarks::Type::Missed; + R.PassName = "pass"; + R.RemarkName = "name"; + R.FunctionName = "func"; + R.Loc = remarks::RemarkLocation{"path", 3, 4}; + R.Args.emplace_back(); + R.Args.back().Key = "keydebug"; + R.Args.back().Val = "valuedebug"; + R.Args.back().Loc = remarks::RemarkLocation{"argpath", 6, 7}; + + // Check that internalize starts using the strings from the string table. + remarks::Remark R2 = R.clone(); + StrTab.internalize(R2); + + // Check that the pointers in the remarks are different. + EXPECT_NE(R.PassName.data(), R2.PassName.data()); + EXPECT_NE(R.RemarkName.data(), R2.RemarkName.data()); + EXPECT_NE(R.FunctionName.data(), R2.FunctionName.data()); + EXPECT_NE(R.Loc->SourceFilePath.data(), R2.Loc->SourceFilePath.data()); + EXPECT_NE(R.Args.back().Key.data(), R2.Args.back().Key.data()); + EXPECT_NE(R.Args.back().Val.data(), R2.Args.back().Val.data()); + EXPECT_NE(R.Args.back().Loc->SourceFilePath.data(), + R2.Args.back().Loc->SourceFilePath.data()); + + // Check that the internalized remark is using the pointers from the string table. + EXPECT_EQ(StrTab.add(R.PassName).second.data(), R2.PassName.data()); + EXPECT_EQ(StrTab.add(R.RemarkName).second.data(), R2.RemarkName.data()); + EXPECT_EQ(StrTab.add(R.FunctionName).second.data(), R2.FunctionName.data()); + EXPECT_EQ(StrTab.add(R.Loc->SourceFilePath).second.data(), + R2.Loc->SourceFilePath.data()); + EXPECT_EQ(StrTab.add(R.Args.back().Key).second.data(), + R2.Args.back().Key.data()); + EXPECT_EQ(StrTab.add(R.Args.back().Val).second.data(), + R2.Args.back().Val.data()); + EXPECT_EQ(StrTab.add(R.Args.back().Loc->SourceFilePath).second.data(), + R2.Args.back().Loc->SourceFilePath.data()); +} -- 2.7.4