diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h --- a/llvm/include/llvm/ProfileData/InstrProf.h +++ b/llvm/include/llvm/ProfileData/InstrProf.h @@ -16,6 +16,7 @@ #define LLVM_PROFILEDATA_INSTRPROF_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" @@ -277,6 +278,16 @@ /// the duplicated profile variables for Comdat functions. bool needsComdatForCounter(const Function &F, const Module &M); +/// An enum describing the attributes of an instrumented profile. +enum class InstrProfKind { + Unknown = 0x0, + FE = 0x1, // A frontend clang profile, incompatible with other attrs. + IR = 0x2, // An IR-level profile (default when -fprofile-generate is used). + BB = 0x4, // A profile with entry basic block instrumentation. + CS = 0x8, // A context sensitive IR-level profile. + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/CS) +}; + const std::error_category &instrprof_category(); enum class instrprof_error { diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h --- a/llvm/include/llvm/ProfileData/InstrProfReader.h +++ b/llvm/include/llvm/ProfileData/InstrProfReader.h @@ -100,6 +100,10 @@ /// Return true if we must provide debug info to create PGO profiles. virtual bool useDebugInfoCorrelate() const { return false; } + /// Returns a BitsetEnum describing the attributes of the profile. To check + /// individual attributes prefer using the helpers above. + virtual InstrProfKind getProfileKind() const = 0; + /// Return the PGO symtab. There are three different readers: /// Raw, Text, and Indexed profile readers. The first two types /// of readers are used only by llvm-profdata tool, while the indexed @@ -176,9 +180,8 @@ std::unique_ptr DataBuffer; /// Iterator over the profile data. line_iterator Line; - bool IsIRLevelProfile = false; - bool HasCSIRLevelProfile = false; - bool InstrEntryBBEnabled = false; + /// The attributes of the current profile. + InstrProfKind ProfileKind = InstrProfKind::Unknown; Error readValueProfileData(InstrProfRecord &Record); @@ -191,11 +194,19 @@ /// Return true if the given buffer is in text instrprof format. static bool hasFormat(const MemoryBuffer &Buffer); - bool isIRLevelProfile() const override { return IsIRLevelProfile; } + bool isIRLevelProfile() const override { + return static_cast(ProfileKind & InstrProfKind::IR); + } + + bool hasCSIRLevelProfile() const override { + return static_cast(ProfileKind & InstrProfKind::CS); + } - bool hasCSIRLevelProfile() const override { return HasCSIRLevelProfile; } + bool instrEntryBBEnabled() const override { + return static_cast(ProfileKind & InstrProfKind::BB); + } - bool instrEntryBBEnabled() const override { return InstrEntryBBEnabled; } + InstrProfKind getProfileKind() const override { return ProfileKind; } /// Read the header. Error readHeader() override; @@ -276,6 +287,21 @@ return (Version & VARIANT_MASK_DBG_CORRELATE) != 0; } + /// Returns a BitsetEnum describing the attributes of the raw instr profile. + InstrProfKind getProfileKind() const override { + InstrProfKind ProfileKind = InstrProfKind::Unknown; + if (Version & VARIANT_MASK_IR_PROF) { + ProfileKind |= InstrProfKind::IR; + } + if (Version & VARIANT_MASK_CSIR_PROF) { + ProfileKind |= InstrProfKind::CS; + } + if (Version & VARIANT_MASK_INSTR_ENTRY) { + ProfileKind |= InstrProfKind::BB; + } + return ProfileKind; + } + InstrProfSymtab &getSymtab() override { assert(Symtab.get()); return *Symtab.get(); @@ -413,6 +439,7 @@ virtual bool isIRLevelProfile() const = 0; virtual bool hasCSIRLevelProfile() const = 0; virtual bool instrEntryBBEnabled() const = 0; + virtual InstrProfKind getProfileKind() const = 0; virtual Error populateSymtab(InstrProfSymtab &) = 0; }; @@ -465,6 +492,20 @@ return (FormatVersion & VARIANT_MASK_INSTR_ENTRY) != 0; } + InstrProfKind getProfileKind() const override { + InstrProfKind ProfileKind = InstrProfKind::Unknown; + if (FormatVersion & VARIANT_MASK_IR_PROF) { + ProfileKind |= InstrProfKind::IR; + } + if (FormatVersion & VARIANT_MASK_CSIR_PROF) { + ProfileKind |= InstrProfKind::CS; + } + if (FormatVersion & VARIANT_MASK_INSTR_ENTRY) { + ProfileKind |= InstrProfKind::BB; + } + return ProfileKind; + } + Error populateSymtab(InstrProfSymtab &Symtab) override { return Symtab.create(HashTable->keys()); } @@ -523,6 +564,12 @@ return Index->instrEntryBBEnabled(); } + /// Returns a BitsetEnum describing the attributes of the indexed instr + /// profile. + InstrProfKind getProfileKind() const override { + return Index->getProfileKind(); + } + /// Return true if the given buffer is in an indexed instrprof format. static bool hasFormat(const MemoryBuffer &DataBuffer); diff --git a/llvm/include/llvm/ProfileData/InstrProfWriter.h b/llvm/include/llvm/ProfileData/InstrProfWriter.h --- a/llvm/include/llvm/ProfileData/InstrProfWriter.h +++ b/llvm/include/llvm/ProfileData/InstrProfWriter.h @@ -33,19 +33,17 @@ class InstrProfWriter { public: using ProfilingData = SmallDenseMap; - // PF_IRLevelWithCS is the profile from context sensitive IR instrumentation. - enum ProfKind { PF_Unknown = 0, PF_FE, PF_IRLevel, PF_IRLevelWithCS }; private: bool Sparse; StringMap FunctionData; - ProfKind ProfileKind = PF_Unknown; - bool InstrEntryBBEnabled; + // An enum describing the attributes of the profile. + InstrProfKind ProfileKind = InstrProfKind::Unknown; // Use raw pointer here for the incomplete type object. InstrProfRecordWriterTrait *InfoObj; public: - InstrProfWriter(bool Sparse = false, bool InstrEntryBBEnabled = false); + InstrProfWriter(bool Sparse = false); ~InstrProfWriter(); StringMap &getProfileData() { return FunctionData; } @@ -79,30 +77,28 @@ /// Write the profile, returning the raw data. For testing. std::unique_ptr writeBuffer(); - /// Set the ProfileKind. Report error if mixing FE and IR level profiles. - /// \c WithCS indicates if this is for contenxt sensitive instrumentation. - Error setIsIRLevelProfile(bool IsIRLevel, bool WithCS) { - if (ProfileKind == PF_Unknown) { - if (IsIRLevel) - ProfileKind = WithCS ? PF_IRLevelWithCS : PF_IRLevel; - else - ProfileKind = PF_FE; + /// Update the attributes of the current profile from the attributes + /// specified. An error is returned if IR and FE profiles are mixed. + Error mergeProfileKind(const InstrProfKind Other) { + // If the kind is unset, this is the first profile we are merging so just + // set it to the given type. + if (ProfileKind == InstrProfKind::Unknown) { + ProfileKind = Other; return Error::success(); } - if (((ProfileKind != PF_FE) && !IsIRLevel) || - ((ProfileKind == PF_FE) && IsIRLevel)) + // Check if the profiles are in-compatible. Clang frontend profiles can't be + // merged with other profile types. + if (static_cast((ProfileKind & InstrProfKind::FE) ^ + (Other & InstrProfKind::FE))) { return make_error(instrprof_error::unsupported_version); + } - // When merging a context-sensitive profile (WithCS == true) with an IRLevel - // profile, set the kind to PF_IRLevelWithCS. - if (ProfileKind == PF_IRLevel && WithCS) - ProfileKind = PF_IRLevelWithCS; - + // Now we update the profile type with the bits that are set. + ProfileKind |= Other; return Error::success(); } - void setInstrEntryBBEnabled(bool Enabled) { InstrEntryBBEnabled = Enabled; } // Internal interface for testing purpose only. void setValueProfDataEndianness(support::endianness Endianness); void setOutputSparse(bool Sparse); diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp --- a/llvm/lib/ProfileData/InstrProfReader.cpp +++ b/llvm/lib/ProfileData/InstrProfReader.cpp @@ -154,30 +154,24 @@ // with a leading ':' will be reported an error format. Error TextInstrProfReader::readHeader() { Symtab.reset(new InstrProfSymtab()); - bool IsIRInstr = false; - bool IsEntryFirst = false; - bool IsCS = false; while (Line->startswith(":")) { StringRef Str = Line->substr(1); if (Str.equals_insensitive("ir")) - IsIRInstr = true; + ProfileKind |= InstrProfKind::IR; else if (Str.equals_insensitive("fe")) - IsIRInstr = false; + ProfileKind |= InstrProfKind::FE; else if (Str.equals_insensitive("csir")) { - IsIRInstr = true; - IsCS = true; + ProfileKind |= InstrProfKind::IR; + ProfileKind |= InstrProfKind::CS; } else if (Str.equals_insensitive("entry_first")) - IsEntryFirst = true; + ProfileKind |= InstrProfKind::BB; else if (Str.equals_insensitive("not_entry_first")) - IsEntryFirst = false; + ProfileKind &= ~InstrProfKind::BB; else return error(instrprof_error::bad_header); ++Line; } - IsIRLevelProfile = IsIRInstr; - InstrEntryBBEnabled = IsEntryFirst; - HasCSIRLevelProfile = IsCS; return success(); } diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp --- a/llvm/lib/ProfileData/InstrProfWriter.cpp +++ b/llvm/lib/ProfileData/InstrProfWriter.cpp @@ -166,9 +166,8 @@ } // end namespace llvm -InstrProfWriter::InstrProfWriter(bool Sparse, bool InstrEntryBBEnabled) - : Sparse(Sparse), InstrEntryBBEnabled(InstrEntryBBEnabled), - InfoObj(new InstrProfRecordWriterTrait()) {} +InstrProfWriter::InstrProfWriter(bool Sparse) + : Sparse(Sparse), InfoObj(new InstrProfRecordWriterTrait()) {} InstrProfWriter::~InstrProfWriter() { delete InfoObj; } @@ -303,13 +302,11 @@ IndexedInstrProf::Header Header; Header.Magic = IndexedInstrProf::Magic; Header.Version = IndexedInstrProf::ProfVersion::CurrentVersion; - if (ProfileKind == PF_IRLevel) - Header.Version |= VARIANT_MASK_IR_PROF; - if (ProfileKind == PF_IRLevelWithCS) { + if (static_cast(ProfileKind & InstrProfKind::IR)) Header.Version |= VARIANT_MASK_IR_PROF; + if (static_cast(ProfileKind & InstrProfKind::CS)) Header.Version |= VARIANT_MASK_CSIR_PROF; - } - if (InstrEntryBBEnabled) + if (static_cast(ProfileKind & InstrProfKind::BB)) Header.Version |= VARIANT_MASK_INSTR_ENTRY; Header.Unused = 0; @@ -337,7 +334,7 @@ OS.write(0); uint64_t CSSummaryOffset = 0; uint64_t CSSummarySize = 0; - if (ProfileKind == PF_IRLevelWithCS) { + if (static_cast(ProfileKind & InstrProfKind::CS)) { CSSummaryOffset = OS.tell(); CSSummarySize = SummarySize / sizeof(uint64_t); for (unsigned I = 0; I < CSSummarySize; I++) @@ -358,7 +355,7 @@ // For Context Sensitive summary. std::unique_ptr TheCSSummary = nullptr; - if (ProfileKind == PF_IRLevelWithCS) { + if (static_cast(ProfileKind & InstrProfKind::CS)) { TheCSSummary = IndexedInstrProf::allocSummary(SummarySize); std::unique_ptr CSPS = CSISB.getSummary(); setSummary(TheCSSummary.get(), *CSPS); @@ -470,11 +467,13 @@ } Error InstrProfWriter::writeText(raw_fd_ostream &OS) { - if (ProfileKind == PF_IRLevel) - OS << "# IR level Instrumentation Flag\n:ir\n"; - else if (ProfileKind == PF_IRLevelWithCS) + // Check CS first since it implies an IR level profile. + if (static_cast(ProfileKind & InstrProfKind::CS)) OS << "# CSIR level Instrumentation Flag\n:csir\n"; - if (InstrEntryBBEnabled) + else if (static_cast(ProfileKind & InstrProfKind::IR)) + OS << "# IR level Instrumentation Flag\n:ir\n"; + + if (static_cast(ProfileKind & InstrProfKind::BB)) OS << "# Always instrument the function entry block\n:entry_first\n"; InstrProfSymtab Symtab; diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -255,9 +255,7 @@ } auto Reader = std::move(ReaderOrErr.get()); - bool IsIRProfile = Reader->isIRLevelProfile(); - bool HasCSIRProfile = Reader->hasCSIRLevelProfile(); - if (Error E = WC->Writer.setIsIRLevelProfile(IsIRProfile, HasCSIRProfile)) { + if (Error E = WC->Writer.mergeProfileKind(Reader->getProfileKind())) { consumeError(std::move(E)); WC->Errors.emplace_back( make_error( @@ -266,7 +264,6 @@ Filename); return; } - WC->Writer.setInstrEntryBBEnabled(Reader->instrEntryBBEnabled()); for (auto &I : *Reader) { if (Remapper)