38
38
#include " llvm/Support/Endian.h"
39
39
#include " llvm/Support/Error.h"
40
40
#include " llvm/Support/ErrorHandling.h"
41
+ #include " llvm/Support/FormatVariadic.h"
41
42
#include " llvm/Support/LEB128.h"
42
43
#include " llvm/Support/MathExtras.h"
43
44
#include " llvm/Support/Path.h"
@@ -165,6 +166,11 @@ static std::string getInstrProfErrString(instrprof_error Err,
165
166
case instrprof_error::counter_value_too_large:
166
167
OS << " excessively large counter value suggests corrupted profile data" ;
167
168
break ;
169
+ case instrprof_error::unsupported_incompatible_future_version:
170
+ OS << " unsupported incompatible future version. The profile is likely "
171
+ " generated from newer released compilers/tools and not parsable by "
172
+ " current reader." ;
173
+ break ;
168
174
}
169
175
170
176
// If optional error message is not empty, append it to the message.
@@ -1612,37 +1618,49 @@ Expected<Header> Header::readFromBuffer(const unsigned char *Buffer) {
1612
1618
1613
1619
// Read the version.
1614
1620
H.Version = read (Buffer, sizeof (uint64_t ));
1615
- uint64_t ProfileVersion = GET_VERSION (H.formatVersion ());
1616
-
1617
- if (ProfileVersion > IndexedInstrProf::ProfVersion::CurrentVersion) {
1618
- if (CurrentVersion < ProfVersion::Version13)
1619
- return make_error<InstrProfError>(instrprof_error::unsupported_version);
1620
-
1621
- // FIXME: When the semantic of an existing payload section changes, allowing
1622
- // profile reader to interpret new profiles using the old code in the
1623
- // current way is too error-prone.
1624
- // Should the payload section record its own version and fail the profile
1625
- // reader to require a re-build of the profile reader in this case?
1621
+ uint64_t ProfileRecordedProfileVersion = GET_VERSION (H.formatVersion ());
1622
+
1623
+ if (ProfileRecordedProfileVersion >= ProfVersion::Version13) {
1624
+ // Starting from version 13, profiles should records header's on-disk byte
1625
+ // size and the minimum profile reader version required.
1626
+ H.OnDiskByteSize = read (Buffer, kOnDiskSizeOffset );
1627
+ H.MinimumProfileReaderVersion =
1628
+ read (Buffer, kOnDiskSizeOffset + sizeof (uint64_t ));
1629
+ } else {
1630
+ // Prior to version 13, the largest version supported by the reader
1631
+ // (ProfVersion::CurrentVersion) must be greater than or equal to the
1632
+ // profile-recorded version.
1633
+ H.MinimumProfileReaderVersion = ProfileRecordedProfileVersion;
1626
1634
}
1627
1635
1628
- if (ProfileVersion >= ProfVersion::Version13)
1629
- H.Size = read (Buffer, kOnDiskSizeOffset );
1636
+ // Stop reading and return error if the largest version supported by the
1637
+ // reader falls behind the minimum reader version required by the profiles.
1638
+ if (IndexedInstrProf::ProfVersion::CurrentVersion <
1639
+ H.MinimumProfileReaderVersion )
1640
+ return make_error<InstrProfError>(
1641
+ instrprof_error::unsupported_incompatible_future_version,
1642
+ formatv (" Profile reader should support {0} to parse profile of version "
1643
+ " {1} " ,
1644
+ H.MinimumProfileReaderVersion , ProfileRecordedProfileVersion));
1630
1645
1631
1646
// `FieldByteOffset` represents the end byte of the last known header field.
1632
1647
auto FieldByteOffsetOrErr = H.knownFieldsEndByteOffset ();
1633
- if (FieldByteOffsetOrErr)
1648
+ if (Error E = FieldByteOffsetOrErr.takeError ())
1649
+ return E;
1650
+
1651
+ auto FieldByteOffset = FieldByteOffsetOrErr.get ();
1634
1652
1635
1653
assert (FieldByteOffset != 0 &&
1636
1654
" FieldByteOffset specifies the byte offset of the last known field in "
1637
1655
" header and should not be zero" );
1638
1656
1639
1657
// If the version from profile is higher than the currently supported version,
1640
1658
// read the known defined header fields and discard the rest.
1641
- if (ProfileVersion > ProfVersion::CurrentVersion)
1642
- ProfileVersion = ProfVersion::CurrentVersion;
1659
+ if (ProfileRecordedProfileVersion > ProfVersion::CurrentVersion)
1660
+ ProfileRecordedProfileVersion = ProfVersion::CurrentVersion;
1643
1661
1644
1662
// Initialize header fields based on the currently supported version.
1645
- switch (ProfileVersion ) {
1663
+ switch (ProfileRecordedProfileVersion ) {
1646
1664
// When a new field is added in the header add a case statement here to
1647
1665
// populate it.
1648
1666
static_assert (
@@ -1651,7 +1669,8 @@ Expected<Header> Header::readFromBuffer(const unsigned char *Buffer) {
1651
1669
" if not add a case statement to fall through to the latest version." );
1652
1670
case 13ull :
1653
1671
// Size field is already read.
1654
- FieldByteOffset -= sizeof (Header::Size);
1672
+ FieldByteOffset -= sizeof (Header::OnDiskByteSize);
1673
+ FieldByteOffset -= sizeof (Header::MinimumProfileReaderVersion);
1655
1674
[[fallthrough]];
1656
1675
case 12ull :
1657
1676
FieldByteOffset -= sizeof (Header::VTableNamesOffset);
@@ -1682,21 +1701,23 @@ Expected<Header> Header::readFromBuffer(const unsigned char *Buffer) {
1682
1701
}
1683
1702
1684
1703
Expected<size_t > Header::knownFieldsEndByteOffset () const {
1685
- const uint64_t ProfileVersion = GET_VERSION (formatVersion ());
1686
- if (ProfileVersion <= ProfVersion::Version12)
1704
+ // All header fields are known before, so the end byte offset of known fields
1705
+ // is the same as header byte size.
1706
+ const uint64_t ProfileRecordedProfileVersion = GET_VERSION (formatVersion ());
1707
+ if (ProfileRecordedProfileVersion <= ProfVersion::Version12)
1687
1708
return this ->size ();
1688
1709
1689
- // Starting from version 13, the known field end byte offset is inferred based
1690
- // on the currently supported version.
1710
+ // Starting from version 13, the known field end byte offset is calculated
1711
+ // based on the currently supported version recorded in the reader .
1691
1712
switch (IndexedInstrProf::ProfVersion::CurrentVersion) {
1692
1713
// When a new field is added in the header add a case statement here to
1693
1714
// populate it.
1694
- static_assert (
1695
- IndexedInstrProf::ProfVersion::CurrentVersion == Version13,
1696
- " Please update the reading code below if a new field has been added, "
1697
- " if not add a case statement to fall through to the latest version." );
1715
+ static_assert (IndexedInstrProf::ProfVersion::CurrentVersion == Version13,
1716
+ " If current version bumps, please update the case below to "
1717
+ " calculate the known field end byte offset." );
1698
1718
case 13ull :
1699
- return kOnDiskSizeOffset + sizeof (Header::Size);
1719
+ return kOnDiskSizeOffset + sizeof (Header::OnDiskByteSize) +
1720
+ sizeof (Header::MinimumProfileReaderVersion);
1700
1721
default :
1701
1722
break ;
1702
1723
}
@@ -1705,16 +1726,17 @@ Expected<size_t> Header::knownFieldsEndByteOffset() const {
1705
1726
}
1706
1727
1707
1728
size_t Header::size () const {
1708
- const uint64_t ProfileVersion = GET_VERSION (formatVersion ());
1729
+ const uint64_t ProfileRecordedProfileVersion = GET_VERSION (formatVersion ());
1709
1730
// Starting from version 13, the indexed profile records the byte size of
1710
1731
// header.
1711
- if (ProfileVersion >= ProfVersion::Version13) {
1712
- assert (Size != 0 && " User can call Header::size() only after reading it "
1713
- " from readMemoryBuffer" );
1714
- return Size;
1732
+ if (ProfileRecordedProfileVersion >= ProfVersion::Version13) {
1733
+ assert (OnDiskByteSize != 0 &&
1734
+ " User can call Header::size() only after reading it "
1735
+ " from readMemoryBuffer" );
1736
+ return OnDiskByteSize;
1715
1737
}
1716
- switch (ProfileVersion ) {
1717
- assert (ProfileVersion <= ProfVersion::Version12 &&
1738
+ switch (ProfileRecordedProfileVersion ) {
1739
+ assert (ProfileRecordedProfileVersion <= ProfVersion::Version12 &&
1718
1740
" Do not infer header size field for newer version" );
1719
1741
case 12ull :
1720
1742
return offsetOf (&Header::VTableNamesOffset) +
0 commit comments