Skip to content

Commit 14cc41a

Browse files
committed
[InstrProf] Make the IndexedInstrProf header backwards compatible.
While the contents of the profile are backwards compatible the header itself is not. For example, when adding new fields to the header results in significant issues. This change adds allows for portable instantiation of the header across indexed format versions. Differential Revision: https://reviews.llvm.org/D118390
1 parent 9b67165 commit 14cc41a

File tree

3 files changed

+76
-18
lines changed

3 files changed

+76
-18
lines changed

llvm/include/llvm/ProfileData/InstrProf.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,16 @@ struct Header {
10281028
uint64_t Unused; // Becomes unused since version 4
10291029
uint64_t HashType;
10301030
uint64_t HashOffset;
1031+
// New fields should only be added at the end to ensure that the size
1032+
// computation is correct. The methods below need to be updated to ensure that
1033+
// the new field is read correctly.
1034+
1035+
// Reads a header struct from the buffer.
1036+
static Expected<Header> readFromBuffer(const unsigned char *Buffer);
1037+
1038+
// Returns the size of the header in bytes for all valid fields based on the
1039+
// version. I.e a older version header will return a smaller size.
1040+
size_t size() const;
10311041
};
10321042

10331043
// Profile summary data recorded in the profile data file in indexed

llvm/lib/ProfileData/InstrProf.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include <memory>
5252
#include <string>
5353
#include <system_error>
54+
#include <type_traits>
5455
#include <utility>
5556
#include <vector>
5657

@@ -1311,4 +1312,59 @@ void OverlapStats::dump(raw_fd_ostream &OS) const {
13111312
}
13121313
}
13131314

1315+
namespace IndexedInstrProf {
1316+
// A C++14 compatible version of the offsetof macro.
1317+
template <typename T1, typename T2>
1318+
inline size_t constexpr offsetOf(T1 T2::*Member) {
1319+
constexpr T2 Object{};
1320+
return size_t(&(Object.*Member)) - size_t(&Object);
1321+
}
1322+
1323+
static inline uint64_t read(const unsigned char *Buffer, size_t Offset) {
1324+
return *reinterpret_cast<const uint64_t *>(Buffer + Offset);
1325+
}
1326+
1327+
Expected<Header> Header::readFromBuffer(const unsigned char *Buffer) {
1328+
using namespace support;
1329+
static_assert(std::is_standard_layout<Header>::value,
1330+
"The header should be standard layout type since we use offset "
1331+
"of fields to read.");
1332+
Header H;
1333+
1334+
H.Magic = read(Buffer, offsetOf(&Header::Magic));
1335+
// Check the magic number.
1336+
uint64_t Magic = endian::byte_swap<uint64_t, little>(H.Magic);
1337+
if (Magic != IndexedInstrProf::Magic)
1338+
return make_error<InstrProfError>(instrprof_error::bad_magic);
1339+
1340+
// Read the version.
1341+
H.Version = read(Buffer, offsetOf(&Header::Version));
1342+
uint64_t FormatVersion = endian::byte_swap<uint64_t, little>(H.Version);
1343+
if (GET_VERSION(FormatVersion) >
1344+
IndexedInstrProf::ProfVersion::CurrentVersion)
1345+
return make_error<InstrProfError>(instrprof_error::unsupported_version);
1346+
1347+
switch (GET_VERSION(FormatVersion)) {
1348+
// When a new field is added in the header add a case statement here to
1349+
// populate it.
1350+
default:
1351+
H.HashType = read(Buffer, offsetOf(&Header::HashType));
1352+
H.HashOffset = read(Buffer, offsetOf(&Header::HashOffset));
1353+
}
1354+
1355+
return H;
1356+
}
1357+
1358+
size_t Header::size() const {
1359+
switch (GET_VERSION(Version)) {
1360+
// When a new field is added to the header add a case statement here to
1361+
// compute the size as offset of the new field + size of the new field. This
1362+
// relies on the field being added to the end of the list.
1363+
default:
1364+
return offsetOf(&Header::HashOffset) + sizeof(Header::HashOffset);
1365+
}
1366+
}
1367+
1368+
} // namespace IndexedInstrProf
1369+
13141370
} // end namespace llvm

llvm/lib/ProfileData/InstrProfReader.cpp

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -934,24 +934,17 @@ Error IndexedInstrProfReader::readHeader() {
934934
if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
935935
return error(instrprof_error::truncated);
936936

937-
auto *Header = reinterpret_cast<const IndexedInstrProf::Header *>(Cur);
938-
Cur += sizeof(IndexedInstrProf::Header);
937+
auto HeaderOr = IndexedInstrProf::Header::readFromBuffer(Start);
938+
if (!HeaderOr)
939+
return HeaderOr.takeError();
939940

940-
// Check the magic number.
941-
uint64_t Magic = endian::byte_swap<uint64_t, little>(Header->Magic);
942-
if (Magic != IndexedInstrProf::Magic)
943-
return error(instrprof_error::bad_magic);
944-
945-
// Read the version.
946-
uint64_t FormatVersion = endian::byte_swap<uint64_t, little>(Header->Version);
947-
if (GET_VERSION(FormatVersion) >
948-
IndexedInstrProf::ProfVersion::CurrentVersion)
949-
return error(instrprof_error::unsupported_version);
941+
const IndexedInstrProf::Header *Header = &HeaderOr.get();
942+
Cur += Header->size();
950943

951-
Cur = readSummary((IndexedInstrProf::ProfVersion)FormatVersion, Cur,
944+
Cur = readSummary((IndexedInstrProf::ProfVersion)Header->Version, Cur,
952945
/* UseCS */ false);
953-
if (FormatVersion & VARIANT_MASK_CSIR_PROF)
954-
Cur = readSummary((IndexedInstrProf::ProfVersion)FormatVersion, Cur,
946+
if (Header->Version & VARIANT_MASK_CSIR_PROF)
947+
Cur = readSummary((IndexedInstrProf::ProfVersion)Header->Version, Cur,
955948
/* UseCS */ true);
956949

957950
// Read the hash type and start offset.
@@ -963,9 +956,8 @@ Error IndexedInstrProfReader::readHeader() {
963956
uint64_t HashOffset = endian::byte_swap<uint64_t, little>(Header->HashOffset);
964957

965958
// The rest of the file is an on disk hash table.
966-
auto IndexPtr =
967-
std::make_unique<InstrProfReaderIndex<OnDiskHashTableImplV3>>(
968-
Start + HashOffset, Cur, Start, HashType, FormatVersion);
959+
auto IndexPtr = std::make_unique<InstrProfReaderIndex<OnDiskHashTableImplV3>>(
960+
Start + HashOffset, Cur, Start, HashType, Header->Version);
969961

970962
// Load the remapping table now if requested.
971963
if (RemappingBuffer) {

0 commit comments

Comments
 (0)