diff --git a/include/llvm/ProfileData/Coverage/CoverageMapping.h b/include/llvm/ProfileData/Coverage/CoverageMapping.h index 56be7ac0f5d..08d1cdf3b2e 100644 --- a/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -23,13 +23,13 @@ #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" -#include "llvm/Support/ErrorOr.h" #include "llvm/Support/raw_ostream.h" #include #include namespace llvm { namespace coverage { + enum class coveragemap_error { success = 0, eof, @@ -38,14 +38,20 @@ enum class coveragemap_error { truncated, malformed }; -} // end of coverage namespace. -} -namespace std { -template <> -struct is_error_code_enum : std::true_type { +class CoverageMapError : public ProfErrorInfoBase { +public: + CoverageMapError(coveragemap_error Err) + : ProfErrorInfoBase(Err) {} + + std::string message() const override; }; -} + +} // end of coverage namespace. + +template <> char ProfErrorInfoBase::ID; + +} // end of llvm namespace namespace llvm { class IndexedInstrProfReader; @@ -265,7 +271,7 @@ public: /// \brief Return the number of times that a region of code associated with /// this counter was executed. - ErrorOr evaluate(const Counter &C) const; + Expected evaluate(const Counter &C) const; }; /// \brief Code coverage information for a single function. @@ -415,12 +421,12 @@ class CoverageMapping { public: /// \brief Load the coverage mapping using the given readers. - static ErrorOr> + static Expected> load(CoverageMappingReader &CoverageReader, IndexedInstrProfReader &ProfileReader); /// \brief Load the coverage mapping from the given files. - static ErrorOr> + static Expected> load(StringRef ObjectFilename, StringRef ProfileFilename, StringRef Arch = StringRef()); @@ -501,14 +507,13 @@ template struct CovMapFunctionRecordV1 { } // Return the PGO name of the function */ template - std::error_code getFuncName(InstrProfSymtab &ProfileNames, - StringRef &FuncName) const { + Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { IntPtrT NameRef = getFuncNameRef(); uint32_t NameS = support::endian::byte_swap(NameSize); FuncName = ProfileNames.getFuncName(NameRef, NameS); if (NameS && FuncName.empty()) - return coveragemap_error::malformed; - return std::error_code(); + return make_error(coveragemap_error::malformed); + return Error::success(); } }; @@ -530,11 +535,10 @@ struct CovMapFunctionRecord { } // Return the PGO name of the function */ template - std::error_code getFuncName(InstrProfSymtab &ProfileNames, - StringRef &FuncName) const { + Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { uint64_t NameRef = getFuncNameRef(); FuncName = ProfileNames.getFuncName(NameRef); - return std::error_code(); + return Error::success(); } }; diff --git a/include/llvm/ProfileData/Coverage/CoverageMappingReader.h b/include/llvm/ProfileData/Coverage/CoverageMappingReader.h index 709006fb113..ce743a96d1d 100644 --- a/include/llvm/ProfileData/Coverage/CoverageMappingReader.h +++ b/include/llvm/ProfileData/Coverage/CoverageMappingReader.h @@ -69,7 +69,7 @@ public: class CoverageMappingReader { public: - virtual std::error_code readNextRecord(CoverageMappingRecord &Record) = 0; + virtual Error readNextRecord(CoverageMappingRecord &Record) = 0; CoverageMappingIterator begin() { return CoverageMappingIterator(this); } CoverageMappingIterator end() { return CoverageMappingIterator(); } virtual ~CoverageMappingReader() {} @@ -82,10 +82,10 @@ protected: RawCoverageReader(StringRef Data) : Data(Data) {} - std::error_code readULEB128(uint64_t &Result); - std::error_code readIntMax(uint64_t &Result, uint64_t MaxPlus1); - std::error_code readSize(uint64_t &Result); - std::error_code readString(StringRef &Result); + Error readULEB128(uint64_t &Result); + Error readIntMax(uint64_t &Result, uint64_t MaxPlus1); + Error readSize(uint64_t &Result); + Error readString(StringRef &Result); }; /// \brief Reader for the raw coverage filenames. @@ -100,7 +100,7 @@ public: RawCoverageFilenamesReader(StringRef Data, std::vector &Filenames) : RawCoverageReader(Data), Filenames(Filenames) {} - std::error_code read(); + Error read(); }; /// \brief Reader for the raw coverage mapping data. @@ -125,12 +125,12 @@ public: Filenames(Filenames), Expressions(Expressions), MappingRegions(MappingRegions) {} - std::error_code read(); + Error read(); private: - std::error_code decodeCounter(unsigned Value, Counter &C); - std::error_code readCounter(Counter &C); - std::error_code + Error decodeCounter(unsigned Value, Counter &C); + Error readCounter(Counter &C); + Error readMappingRegionsSubArray(std::vector &MappingRegions, unsigned InferredFileID, size_t NumFileIDs); }; @@ -170,11 +170,11 @@ private: BinaryCoverageReader() : CurrentRecord(0) {} public: - static ErrorOr> + static Expected> create(std::unique_ptr &ObjectBuffer, StringRef Arch); - std::error_code readNextRecord(CoverageMappingRecord &Record) override; + Error readNextRecord(CoverageMappingRecord &Record) override; }; } // end namespace coverage diff --git a/include/llvm/ProfileData/InstrProf.h b/include/llvm/ProfileData/InstrProf.h index 1f46650c528..86fab33613b 100644 --- a/include/llvm/ProfileData/InstrProf.h +++ b/include/llvm/ProfileData/InstrProf.h @@ -25,7 +25,6 @@ #include "llvm/ProfileData/ProfileCommon.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/ErrorOr.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" #include @@ -204,20 +203,17 @@ StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName, /// third field is the uncompressed strings; otherwise it is the /// compressed string. When the string compression is off, the /// second field will have value zero. -std::error_code -collectPGOFuncNameStrings(const std::vector &NameStrs, - bool doCompression, std::string &Result); +Error collectPGOFuncNameStrings(const std::vector &NameStrs, + bool doCompression, std::string &Result); /// Produce \c Result string with the same format described above. The input /// is vector of PGO function name variables that are referenced. -std::error_code -collectPGOFuncNameStrings(const std::vector &NameVars, - std::string &Result, bool doCompression = true); +Error collectPGOFuncNameStrings(const std::vector &NameVars, + std::string &Result, bool doCompression = true); class InstrProfSymtab; /// \c NameStrings is a string composed of one of more sub-strings encoded in /// the format described above. The substrings are seperated by 0 or more zero /// bytes. This method decodes the string and populates the \c Symtab. -std::error_code readPGOFuncNameStrings(StringRef NameStrings, - InstrProfSymtab &Symtab); +Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab); enum InstrProfValueKind : uint32_t { #define VALUE_PROF_KIND(Enumerator, Value) Enumerator = Value, @@ -284,6 +280,27 @@ inline std::error_code make_error_code(instrprof_error E) { return std::error_code(static_cast(E), instrprof_category()); } +class InstrProfError : public ProfErrorInfoBase { +public: + InstrProfError(instrprof_error Err) + : ProfErrorInfoBase(Err) {} + + std::string message() const override; + + /// Consume an Error and return the raw enum value contained within it. The + /// Error must either be a success value, or contain a single InstrProfError. + static instrprof_error take(Error E) { + auto Err = instrprof_error::success; + handleAllErrors(std::move(E), [&Err](const InstrProfError &IPE) { + assert(Err == instrprof_error::success && "Multiple errors encountered"); + Err = IPE.get(); + }); + return Err; + } +}; + +template <> char ProfErrorInfoBase::ID; + class SoftInstrProfErrors { /// Count the number of soft instrprof_errors encountered and keep track of /// the first such error for reporting purposes. @@ -309,6 +326,11 @@ public: NumCountMismatches(0), NumCounterOverflows(0), NumValueSiteCountMismatches(0) {} + ~SoftInstrProfErrors() { + assert(FirstError == instrprof_error::success && + "Unchecked soft error encountered"); + } + /// Track a soft error (\p IE) and increment its associated counter. void addError(instrprof_error IE); @@ -326,8 +348,15 @@ public: return NumValueSiteCountMismatches; } - /// Return an error code for the first encountered error. - std::error_code getError() const { return make_error_code(FirstError); } + /// Return the first encountered error and reset FirstError to a success + /// value. + Error takeError() { + if (FirstError == instrprof_error::success) + return Error::success(); + auto E = make_error(FirstError); + FirstError = instrprof_error::success; + return E; + } }; namespace object { @@ -372,14 +401,14 @@ public: /// only initialize the symtab with reference to the data and /// the section base address. The decompression will be delayed /// until before it is used. See also \c create(StringRef) method. - std::error_code create(object::SectionRef &Section); + Error create(object::SectionRef &Section); /// This interface is used by reader of CoverageMapping test /// format. - inline std::error_code create(StringRef D, uint64_t BaseAddr); + inline Error create(StringRef D, uint64_t BaseAddr); /// \c NameStrings is a string composed of one of more sub-strings /// encoded in the format described in \c collectPGOFuncNameStrings. /// This method is a wrapper to \c readPGOFuncNameStrings method. - inline std::error_code create(StringRef NameStrings); + inline Error create(StringRef NameStrings); /// A wrapper interface to populate the PGO symtab with functions /// decls from module \c M. This interface is used by transformation /// passes such as indirect function call promotion. Variable \c InLTO @@ -424,13 +453,13 @@ public: inline StringRef getNameData() const { return Data; } }; -std::error_code InstrProfSymtab::create(StringRef D, uint64_t BaseAddr) { +Error InstrProfSymtab::create(StringRef D, uint64_t BaseAddr) { Data = D; Address = BaseAddr; - return std::error_code(); + return Error::success(); } -std::error_code InstrProfSymtab::create(StringRef NameStrings) { +Error InstrProfSymtab::create(StringRef NameStrings) { return readPGOFuncNameStrings(NameStrings, *this); } @@ -572,7 +601,7 @@ struct InstrProfRecord { } /// Get the error contained within the record's soft error counter. - std::error_code getError() const { return SIPE.getError(); } + Error takeError() { return SIPE.takeError(); } private: std::vector IndirectCallSites; @@ -869,9 +898,4 @@ struct Header { } // end namespace llvm -namespace std { -template <> -struct is_error_code_enum : std::true_type {}; -} - #endif // LLVM_PROFILEDATA_INSTRPROF_H diff --git a/include/llvm/ProfileData/InstrProfData.inc b/include/llvm/ProfileData/InstrProfData.inc index 49c3266c269..a9f3c50bf97 100644 --- a/include/llvm/ProfileData/InstrProfData.inc +++ b/include/llvm/ProfileData/InstrProfData.inc @@ -322,16 +322,15 @@ typedef struct ValueProfData { static std::unique_ptr serializeFrom(const InstrProfRecord &Record); /*! - * Check the integrity of the record. Return the error code when - * an error is detected, otherwise return instrprof_error::success. + * Check the integrity of the record. */ - instrprof_error checkIntegrity(); + Error checkIntegrity(); /*! * Return a pointer to \c ValueProfileData instance ready to be read. * All data in the instance are properly byte swapped. The input * data is assumed to be in little endian order. */ - static ErrorOr> + static Expected> getValueProfData(const unsigned char *SrcBuffer, const unsigned char *const SrcBufferEnd, support::endianness SrcDataEndianness); diff --git a/include/llvm/ProfileData/InstrProfReader.h b/include/llvm/ProfileData/InstrProfReader.h index a5d06264536..4e9e618324a 100644 --- a/include/llvm/ProfileData/InstrProfReader.h +++ b/include/llvm/ProfileData/InstrProfReader.h @@ -19,7 +19,6 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/EndianStream.h" -#include "llvm/Support/ErrorOr.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/OnDiskHashTable.h" @@ -51,16 +50,16 @@ public: /// Base class and interface for reading profiling data of any known instrprof /// format. Provides an iterator over InstrProfRecords. class InstrProfReader { - std::error_code LastError; + instrprof_error LastError; public: InstrProfReader() : LastError(instrprof_error::success), Symtab() {} virtual ~InstrProfReader() {} /// Read the header. Required before reading first record. - virtual std::error_code readHeader() = 0; + virtual Error readHeader() = 0; /// Read a single record. - virtual std::error_code readNextRecord(InstrProfRecord &Record) = 0; + virtual Error readNextRecord(InstrProfRecord &Record) = 0; /// Iterator over profile data. InstrProfIterator begin() { return InstrProfIterator(this); } InstrProfIterator end() { return InstrProfIterator(); } @@ -80,28 +79,35 @@ public: protected: std::unique_ptr Symtab; - /// Set the current std::error_code and return same. - std::error_code error(std::error_code EC) { - LastError = EC; - return EC; + /// Set the current error and return same. + Error error(instrprof_error Err) { + LastError = Err; + if (Err == instrprof_error::success) + return Error::success(); + return make_error(Err); } + Error error(Error E) { return error(InstrProfError::take(std::move(E))); } - /// Clear the current error code and return a successful one. - std::error_code success() { return error(instrprof_error::success); } + /// Clear the current error and return a successful one. + Error success() { return error(instrprof_error::success); } public: /// Return true if the reader has finished reading the profile data. bool isEOF() { return LastError == instrprof_error::eof; } /// Return true if the reader encountered an error reading profiling data. - bool hasError() { return LastError && !isEOF(); } - /// Get the current error code. - std::error_code getError() { return LastError; } + bool hasError() { return LastError != instrprof_error::success && !isEOF(); } + /// Get the current error. + Error getError() { + if (hasError()) + return make_error(LastError); + return Error::success(); + } /// Factory method to create an appropriately typed reader for the given /// instrprof file. - static ErrorOr> create(std::string Path); + static Expected> create(std::string Path); - static ErrorOr> + static Expected> create(std::unique_ptr Buffer); }; @@ -123,7 +129,7 @@ private: TextInstrProfReader(const TextInstrProfReader &) = delete; TextInstrProfReader &operator=(const TextInstrProfReader &) = delete; - std::error_code readValueProfileData(InstrProfRecord &Record); + Error readValueProfileData(InstrProfRecord &Record); public: TextInstrProfReader(std::unique_ptr DataBuffer_) @@ -136,9 +142,9 @@ public: bool isIRLevelProfile() const override { return IsIRLevelProfile; } /// Read the header. - std::error_code readHeader() override; + Error readHeader() override; /// Read a single record. - std::error_code readNextRecord(InstrProfRecord &Record) override; + Error readNextRecord(InstrProfRecord &Record) override; InstrProfSymtab &getSymtab() override { assert(Symtab.get()); @@ -185,8 +191,8 @@ public: : DataBuffer(std::move(DataBuffer)) { } static bool hasFormat(const MemoryBuffer &DataBuffer); - std::error_code readHeader() override; - std::error_code readNextRecord(InstrProfRecord &Record) override; + Error readHeader() override; + Error readNextRecord(InstrProfRecord &Record) override; bool isIRLevelProfile() const override { return (Version & VARIANT_MASK_IR_PROF) != 0; } @@ -197,9 +203,9 @@ public: } private: - std::error_code createSymtab(InstrProfSymtab &Symtab); - std::error_code readNextHeader(const char *CurrentPos); - std::error_code readHeader(const RawInstrProf::Header &Header); + Error createSymtab(InstrProfSymtab &Symtab); + Error readNextHeader(const char *CurrentPos); + Error readHeader(const RawInstrProf::Header &Header); template IntT swap(IntT Int) const { return ShouldSwapBytes ? sys::getSwappedBytes(Int) : Int; } @@ -216,10 +222,10 @@ private: inline uint8_t getNumPaddingBytes(uint64_t SizeInBytes) { return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t)); } - std::error_code readName(InstrProfRecord &Record); - std::error_code readFuncHash(InstrProfRecord &Record); - std::error_code readRawCounts(InstrProfRecord &Record); - std::error_code readValueProfilingData(InstrProfRecord &Record); + Error readName(InstrProfRecord &Record); + Error readFuncHash(InstrProfRecord &Record); + Error readRawCounts(InstrProfRecord &Record); + Error readValueProfilingData(InstrProfRecord &Record); bool atEnd() const { return Data == DataEnd; } void advanceData() { Data++; @@ -300,9 +306,9 @@ public: struct InstrProfReaderIndexBase { // Read all the profile records with the same key pointed to the current // iterator. - virtual std::error_code getRecords(ArrayRef &Data) = 0; + virtual Error getRecords(ArrayRef &Data) = 0; // Read all the profile records with the key equal to FuncName - virtual std::error_code getRecords(StringRef FuncName, + virtual Error getRecords(StringRef FuncName, ArrayRef &Data) = 0; virtual void advanceToNextKey() = 0; virtual bool atEnd() const = 0; @@ -330,9 +336,9 @@ public: const unsigned char *const Base, IndexedInstrProf::HashT HashType, uint64_t Version); - std::error_code getRecords(ArrayRef &Data) override; - std::error_code getRecords(StringRef FuncName, - ArrayRef &Data) override; + Error getRecords(ArrayRef &Data) override; + Error getRecords(StringRef FuncName, + ArrayRef &Data) override; void advanceToNextKey() override { RecordIterator++; } bool atEnd() const override { return RecordIterator == HashTable->data_end(); @@ -379,27 +385,27 @@ public: static bool hasFormat(const MemoryBuffer &DataBuffer); /// Read the file header. - std::error_code readHeader() override; + Error readHeader() override; /// Read a single record. - std::error_code readNextRecord(InstrProfRecord &Record) override; + Error readNextRecord(InstrProfRecord &Record) override; /// Return the pointer to InstrProfRecord associated with FuncName /// and FuncHash - ErrorOr getInstrProfRecord(StringRef FuncName, - uint64_t FuncHash); + Expected getInstrProfRecord(StringRef FuncName, + uint64_t FuncHash); /// Fill Counts with the profile data for the given function name. - std::error_code getFunctionCounts(StringRef FuncName, uint64_t FuncHash, - std::vector &Counts); + Error getFunctionCounts(StringRef FuncName, uint64_t FuncHash, + std::vector &Counts); /// Return the maximum of all known function counts. uint64_t getMaximumFunctionCount() { return Summary->getMaxFunctionCount(); } /// Factory method to create an indexed reader. - static ErrorOr> + static Expected> create(std::string Path); - static ErrorOr> + static Expected> create(std::unique_ptr Buffer); // Used for testing purpose only. diff --git a/include/llvm/ProfileData/InstrProfWriter.h b/include/llvm/ProfileData/InstrProfWriter.h index 8b02d3cc9ed..7d292731ccc 100644 --- a/include/llvm/ProfileData/InstrProfWriter.h +++ b/include/llvm/ProfileData/InstrProfWriter.h @@ -46,7 +46,7 @@ public: /// Add function counts for the given function. If there are already counts /// for this function and the hash and number of counts match, each counter is /// summed. Optionally scale counts by \p Weight. - std::error_code addRecord(InstrProfRecord &&I, uint64_t Weight = 1); + Error addRecord(InstrProfRecord &&I, uint64_t Weight = 1); /// Write the profile to \c OS void write(raw_fd_ostream &OS); /// Write the profile in text format to \c OS @@ -58,13 +58,15 @@ public: std::unique_ptr writeBuffer(); /// Set the ProfileKind. Report error if mixing FE and IR level profiles. - std::error_code setIsIRLevelProfile(bool IsIRLevel) { + Error setIsIRLevelProfile(bool IsIRLevel) { if (ProfileKind == PF_Unknown) { ProfileKind = IsIRLevel ? PF_IRLevel: PF_FE; - return instrprof_error::success; + return Error::success(); } - return (IsIRLevel == (ProfileKind == PF_IRLevel)) ? - instrprof_error::success : instrprof_error::unsupported_version; + return (IsIRLevel == (ProfileKind == PF_IRLevel)) + ? Error::success() + : make_error( + instrprof_error::unsupported_version); } // Internal interface for testing purpose only. diff --git a/include/llvm/ProfileData/ProfileCommon.h b/include/llvm/ProfileData/ProfileCommon.h index ae196aa5d00..c367b5951c4 100644 --- a/include/llvm/ProfileData/ProfileCommon.h +++ b/include/llvm/ProfileData/ProfileCommon.h @@ -21,6 +21,7 @@ #include #include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" namespace llvm { class Function; @@ -36,6 +37,29 @@ class Metadata; class MDTuple; class MDNode; +template +class ProfErrorInfoBase : public ErrorInfo> { +public: + ProfErrorInfoBase(ErrT Err) : Err(Err) { + assert(Err != ErrT::success && "Not an error"); + } + + virtual std::string message() const override = 0; + + void log(raw_ostream &OS) const override { OS << message(); } + + std::error_code convertToErrorCode() const override { + return make_error_code(Err); + } + + ErrT get() const { return Err; } + + static char ID; + +protected: + ErrT Err; +}; + inline const char *getHotSectionPrefix() { return ".hot"; } inline const char *getUnlikelySectionPrefix() { return ".unlikely"; } diff --git a/lib/ProfileData/Coverage/CoverageMapping.cpp b/lib/ProfileData/Coverage/CoverageMapping.cpp index 9fdd37081c9..7133697bb87 100644 --- a/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -143,28 +143,30 @@ void CounterMappingContext::dump(const Counter &C, } if (CounterValues.empty()) return; - ErrorOr Value = evaluate(C); - if (!Value) + Expected Value = evaluate(C); + if (auto E = Value.takeError()) { + llvm::consumeError(std::move(E)); return; + } OS << '[' << *Value << ']'; } -ErrorOr CounterMappingContext::evaluate(const Counter &C) const { +Expected CounterMappingContext::evaluate(const Counter &C) const { switch (C.getKind()) { case Counter::Zero: return 0; case Counter::CounterValueReference: if (C.getCounterID() >= CounterValues.size()) - return make_error_code(errc::argument_out_of_domain); + return errorCodeToError(errc::argument_out_of_domain); return CounterValues[C.getCounterID()]; case Counter::Expression: { if (C.getExpressionID() >= Expressions.size()) - return make_error_code(errc::argument_out_of_domain); + return errorCodeToError(errc::argument_out_of_domain); const auto &E = Expressions[C.getExpressionID()]; - ErrorOr LHS = evaluate(E.LHS); + Expected LHS = evaluate(E.LHS); if (!LHS) return LHS; - ErrorOr RHS = evaluate(E.RHS); + Expected RHS = evaluate(E.RHS); if (!RHS) return RHS; return E.Kind == CounterExpression::Subtract ? *LHS - *RHS : *LHS + *RHS; @@ -181,7 +183,7 @@ void FunctionRecordIterator::skipOtherFiles() { *this = FunctionRecordIterator(); } -ErrorOr> +Expected> CoverageMapping::load(CoverageMappingReader &CoverageReader, IndexedInstrProfReader &ProfileReader) { auto Coverage = std::unique_ptr(new CoverageMapping()); @@ -191,13 +193,14 @@ CoverageMapping::load(CoverageMappingReader &CoverageReader, CounterMappingContext Ctx(Record.Expressions); Counts.clear(); - if (std::error_code EC = ProfileReader.getFunctionCounts( + if (Error E = ProfileReader.getFunctionCounts( Record.FunctionName, Record.FunctionHash, Counts)) { - if (EC == instrprof_error::hash_mismatch) { + instrprof_error IPE = InstrProfError::take(std::move(E)); + if (IPE == instrprof_error::hash_mismatch) { Coverage->MismatchedFunctionCount++; continue; - } else if (EC != instrprof_error::unknown_function) - return EC; + } else if (IPE != instrprof_error::unknown_function) + return make_error(IPE); Counts.assign(Record.MappingRegions.size(), 0); } Ctx.setCounts(Counts); @@ -212,9 +215,11 @@ CoverageMapping::load(CoverageMappingReader &CoverageReader, getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]); FunctionRecord Function(OrigFuncName, Record.Filenames); for (const auto &Region : Record.MappingRegions) { - ErrorOr ExecutionCount = Ctx.evaluate(Region.Count); - if (!ExecutionCount) + Expected ExecutionCount = Ctx.evaluate(Region.Count); + if (auto E = ExecutionCount.takeError()) { + llvm::consumeError(std::move(E)); break; + } Function.pushRegion(Region, *ExecutionCount); } if (Function.CountedRegions.size() != Record.MappingRegions.size()) { @@ -228,20 +233,20 @@ CoverageMapping::load(CoverageMappingReader &CoverageReader, return std::move(Coverage); } -ErrorOr> +Expected> CoverageMapping::load(StringRef ObjectFilename, StringRef ProfileFilename, StringRef Arch) { auto CounterMappingBuff = MemoryBuffer::getFileOrSTDIN(ObjectFilename); if (std::error_code EC = CounterMappingBuff.getError()) - return EC; + return errorCodeToError(EC); auto CoverageReaderOrErr = BinaryCoverageReader::create(CounterMappingBuff.get(), Arch); - if (std::error_code EC = CoverageReaderOrErr.getError()) - return EC; + if (Error E = CoverageReaderOrErr.takeError()) + return std::move(E); auto CoverageReader = std::move(CoverageReaderOrErr.get()); auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename); - if (auto EC = ProfileReaderOrErr.getError()) - return EC; + if (Error E = ProfileReaderOrErr.takeError()) + return std::move(E); auto ProfileReader = std::move(ProfileReaderOrErr.get()); return load(*CoverageReader, *ProfileReader); } @@ -533,27 +538,34 @@ CoverageMapping::getCoverageForExpansion(const ExpansionRecord &Expansion) { } namespace { +std::string getCoverageMapErrString(coveragemap_error Err) { + switch (Err) { + case coveragemap_error::success: + return "Success"; + case coveragemap_error::eof: + return "End of File"; + case coveragemap_error::no_data_found: + return "No coverage data found"; + case coveragemap_error::unsupported_version: + return "Unsupported coverage format version"; + case coveragemap_error::truncated: + return "Truncated coverage data"; + case coveragemap_error::malformed: + return "Malformed coverage data"; + } + llvm_unreachable("A value of coveragemap_error has no message."); +} + class CoverageMappingErrorCategoryType : public std::error_category { const char *name() const LLVM_NOEXCEPT override { return "llvm.coveragemap"; } std::string message(int IE) const override { - auto E = static_cast(IE); - switch (E) { - case coveragemap_error::success: - return "Success"; - case coveragemap_error::eof: - return "End of File"; - case coveragemap_error::no_data_found: - return "No coverage data found"; - case coveragemap_error::unsupported_version: - return "Unsupported coverage format version"; - case coveragemap_error::truncated: - return "Truncated coverage data"; - case coveragemap_error::malformed: - return "Malformed coverage data"; - } - llvm_unreachable("A value of coveragemap_error has no message."); + return getCoverageMapErrString(static_cast(IE)); } }; +} // end anonymous namespace + +std::string CoverageMapError::message() const { + return getCoverageMapErrString(Err); } static ManagedStatic ErrorCategory; @@ -561,3 +573,5 @@ static ManagedStatic ErrorCategory; const std::error_category &llvm::coverage::coveragemap_category() { return *ErrorCategory; } + +template <> char ProfErrorInfoBase::ID = 0; diff --git a/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/lib/ProfileData/Coverage/CoverageMappingReader.cpp index 9f27de91bc5..999460dd5a8 100644 --- a/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -31,49 +31,54 @@ using namespace object; void CoverageMappingIterator::increment() { // Check if all the records were read or if an error occurred while reading // the next record. - if (Reader->readNextRecord(Record)) - *this = CoverageMappingIterator(); + if (auto E = Reader->readNextRecord(Record)) { + handleAllErrors(std::move(E), [&](const CoverageMapError &CME) { + if (CME.get() == coveragemap_error::eof) + *this = CoverageMappingIterator(); + else + llvm_unreachable("Unexpected error in coverage mapping iterator"); + }); + } } -std::error_code RawCoverageReader::readULEB128(uint64_t &Result) { +Error RawCoverageReader::readULEB128(uint64_t &Result) { if (Data.size() < 1) - return coveragemap_error::truncated; + return make_error(coveragemap_error::truncated); unsigned N = 0; Result = decodeULEB128(reinterpret_cast(Data.data()), &N); if (N > Data.size()) - return coveragemap_error::malformed; + return make_error(coveragemap_error::malformed); Data = Data.substr(N); - return std::error_code(); + return Error::success(); } -std::error_code RawCoverageReader::readIntMax(uint64_t &Result, - uint64_t MaxPlus1) { +Error RawCoverageReader::readIntMax(uint64_t &Result, uint64_t MaxPlus1) { if (auto Err = readULEB128(Result)) return Err; if (Result >= MaxPlus1) - return coveragemap_error::malformed; - return std::error_code(); + return make_error(coveragemap_error::malformed); + return Error::success(); } -std::error_code RawCoverageReader::readSize(uint64_t &Result) { +Error RawCoverageReader::readSize(uint64_t &Result) { if (auto Err = readULEB128(Result)) return Err; // Sanity check the number. if (Result > Data.size()) - return coveragemap_error::malformed; - return std::error_code(); + return make_error(coveragemap_error::malformed); + return Error::success(); } -std::error_code RawCoverageReader::readString(StringRef &Result) { +Error RawCoverageReader::readString(StringRef &Result) { uint64_t Length; if (auto Err = readSize(Length)) return Err; Result = Data.substr(0, Length); Data = Data.substr(Length); - return std::error_code(); + return Error::success(); } -std::error_code RawCoverageFilenamesReader::read() { +Error RawCoverageFilenamesReader::read() { uint64_t NumFilenames; if (auto Err = readSize(NumFilenames)) return Err; @@ -83,19 +88,18 @@ std::error_code RawCoverageFilenamesReader::read() { return Err; Filenames.push_back(Filename); } - return std::error_code(); + return Error::success(); } -std::error_code RawCoverageMappingReader::decodeCounter(unsigned Value, - Counter &C) { +Error RawCoverageMappingReader::decodeCounter(unsigned Value, Counter &C) { auto Tag = Value & Counter::EncodingTagMask; switch (Tag) { case Counter::Zero: C = Counter::getZero(); - return std::error_code(); + return Error::success(); case Counter::CounterValueReference: C = Counter::getCounter(Value >> Counter::EncodingTagBits); - return std::error_code(); + return Error::success(); default: break; } @@ -105,25 +109,25 @@ std::error_code RawCoverageMappingReader::decodeCounter(unsigned Value, case CounterExpression::Add: { auto ID = Value >> Counter::EncodingTagBits; if (ID >= Expressions.size()) - return coveragemap_error::malformed; + return make_error(coveragemap_error::malformed); Expressions[ID].Kind = CounterExpression::ExprKind(Tag); C = Counter::getExpression(ID); break; } default: - return coveragemap_error::malformed; + return make_error(coveragemap_error::malformed); } - return std::error_code(); + return Error::success(); } -std::error_code RawCoverageMappingReader::readCounter(Counter &C) { +Error RawCoverageMappingReader::readCounter(Counter &C) { uint64_t EncodedCounter; if (auto Err = readIntMax(EncodedCounter, std::numeric_limits::max())) return Err; if (auto Err = decodeCounter(EncodedCounter, C)) return Err; - return std::error_code(); + return Error::success(); } static const unsigned EncodingExpansionRegionBit = 1 @@ -132,7 +136,7 @@ static const unsigned EncodingExpansionRegionBit = 1 /// \brief Read the sub-array of regions for the given inferred file id. /// \param NumFileIDs the number of file ids that are defined for this /// function. -std::error_code RawCoverageMappingReader::readMappingRegionsSubArray( +Error RawCoverageMappingReader::readMappingRegionsSubArray( std::vector &MappingRegions, unsigned InferredFileID, size_t NumFileIDs) { uint64_t NumRegions; @@ -160,7 +164,7 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray( ExpandedFileID = EncodedCounterAndRegion >> Counter::EncodingCounterTagAndExpansionRegionTagBits; if (ExpandedFileID >= NumFileIDs) - return coveragemap_error::malformed; + return make_error(coveragemap_error::malformed); } else { switch (EncodedCounterAndRegion >> Counter::EncodingCounterTagAndExpansionRegionTagBits) { @@ -171,7 +175,7 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray( Kind = CounterMappingRegion::SkippedRegion; break; default: - return coveragemap_error::malformed; + return make_error(coveragemap_error::malformed); } } } @@ -184,7 +188,7 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray( if (auto Err = readULEB128(ColumnStart)) return Err; if (ColumnStart > std::numeric_limits::max()) - return coveragemap_error::malformed; + return make_error(coveragemap_error::malformed); if (auto Err = readIntMax(NumLines, std::numeric_limits::max())) return Err; if (auto Err = readIntMax(ColumnEnd, std::numeric_limits::max())) @@ -218,10 +222,10 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray( C, InferredFileID, ExpandedFileID, LineStart, ColumnStart, LineStart + NumLines, ColumnEnd, Kind)); } - return std::error_code(); + return Error::success(); } -std::error_code RawCoverageMappingReader::read() { +Error RawCoverageMappingReader::read() { // Read the virtual file mapping. llvm::SmallVector VirtualFileMapping; @@ -287,14 +291,14 @@ std::error_code RawCoverageMappingReader::read() { } } - return std::error_code(); + return Error::success(); } -std::error_code InstrProfSymtab::create(SectionRef &Section) { - if (auto Err = Section.getContents(Data)) - return Err; +Error InstrProfSymtab::create(SectionRef &Section) { + if (auto EC = Section.getContents(Data)) + return errorCodeToError(EC); Address = Section.getAddress(); - return std::error_code(); + return Error::success(); } StringRef InstrProfSymtab::getFuncName(uint64_t Pointer, size_t Size) { @@ -312,11 +316,10 @@ struct CovMapFuncRecordReader { // a module. \p Buf is a reference to the buffer pointer pointing // to the \c CovHeader of coverage mapping data associated with // the module. - virtual std::error_code readFunctionRecords(const char *&Buf, - const char *End) = 0; + virtual Error readFunctionRecords(const char *&Buf, const char *End) = 0; virtual ~CovMapFuncRecordReader() {} template - static ErrorOr> + static Expected> get(coverage::CovMapVersion Version, InstrProfSymtab &P, std::vector &R, std::vector &F); @@ -344,11 +347,10 @@ public: : ProfileNames(P), Filenames(F), Records(R) {} ~VersionedCovMapFuncRecordReader() override {} - std::error_code readFunctionRecords(const char *&Buf, - const char *End) override { + Error readFunctionRecords(const char *&Buf, const char *End) override { using namespace support; if (Buf + sizeof(CovMapHeader) > End) - return coveragemap_error::malformed; + return make_error(coveragemap_error::malformed); auto CovHeader = reinterpret_cast(Buf); uint32_t NRecords = CovHeader->getNRecords(); uint32_t FilenamesSize = CovHeader->getFilenamesSize(); @@ -363,7 +365,7 @@ public: // Get the filenames. if (Buf + FilenamesSize > End) - return coveragemap_error::malformed; + return make_error(coveragemap_error::malformed); size_t FilenamesBegin = Filenames.size(); RawCoverageFilenamesReader Reader(StringRef(Buf, FilenamesSize), Filenames); if (auto Err = Reader.read()) @@ -376,7 +378,7 @@ public: const char *CovEnd = Buf; if (Buf > End) - return coveragemap_error::malformed; + return make_error(coveragemap_error::malformed); // Each coverage map has an alignment of 8, so we need to adjust alignment // before reading the next map. Buf += alignmentAdjustment(Buf, 8); @@ -389,7 +391,7 @@ public: // Now use that to read the coverage data. if (CovBuf + DataSize > CovEnd) - return coveragemap_error::malformed; + return make_error(coveragemap_error::malformed); auto Mapping = StringRef(CovBuf, DataSize); CovBuf += DataSize; @@ -403,21 +405,20 @@ public: } StringRef FuncName; - if (std::error_code EC = - CFR->template getFuncName(ProfileNames, FuncName)) - return EC; + if (Error E = CFR->template getFuncName(ProfileNames, FuncName)) + return E; Records.push_back(BinaryCoverageReader::ProfileMappingRecord( Version, FuncName, FuncHash, Mapping, FilenamesBegin, Filenames.size() - FilenamesBegin)); CFR++; } - return std::error_code(); + return Error::success(); } }; } // end anonymous namespace template -ErrorOr> CovMapFuncRecordReader::get( +Expected> CovMapFuncRecordReader::get( coverage::CovMapVersion Version, InstrProfSymtab &P, std::vector &R, std::vector &F) { @@ -428,8 +429,8 @@ ErrorOr> CovMapFuncRecordReader::get( CovMapVersion::Version1, IntPtrT, Endian>>(P, R, F); case CovMapVersion::Version2: // Decompress the name data. - if (auto EC = P.create(P.getNameData())) - return EC; + if (Error E = P.create(P.getNameData())) + return std::move(E); return llvm::make_unique>(P, R, F); } @@ -437,7 +438,7 @@ ErrorOr> CovMapFuncRecordReader::get( } template -static std::error_code readCoverageMappingData( +static Error readCoverageMappingData( InstrProfSymtab &ProfileNames, StringRef Data, std::vector &Records, std::vector &Filenames) { @@ -447,89 +448,90 @@ static std::error_code readCoverageMappingData( reinterpret_cast(Data.data()); CovMapVersion Version = (CovMapVersion)CovHeader->getVersion(); if (Version > coverage::CovMapVersion::CurrentVersion) - return coveragemap_error::unsupported_version; - ErrorOr> ReaderErrorOr = + return make_error(coveragemap_error::unsupported_version); + Expected> ReaderExpected = CovMapFuncRecordReader::get(Version, ProfileNames, Records, Filenames); - if (auto EC = ReaderErrorOr.getError()) - return EC; - auto Reader = std::move(ReaderErrorOr.get()); + if (Error E = ReaderExpected.takeError()) + return E; + auto Reader = std::move(ReaderExpected.get()); for (const char *Buf = Data.data(), *End = Buf + Data.size(); Buf < End;) { - if (std::error_code EC = Reader->readFunctionRecords(Buf, End)) - return EC; + if (Error E = Reader->readFunctionRecords(Buf, End)) + return E; } - return std::error_code(); + return Error::success(); } static const char *TestingFormatMagic = "llvmcovmtestdata"; -static std::error_code loadTestingFormat(StringRef Data, - InstrProfSymtab &ProfileNames, - StringRef &CoverageMapping, - uint8_t &BytesInAddress, - support::endianness &Endian) { +static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames, + StringRef &CoverageMapping, + uint8_t &BytesInAddress, + support::endianness &Endian) { BytesInAddress = 8; Endian = support::endianness::little; Data = Data.substr(StringRef(TestingFormatMagic).size()); if (Data.size() < 1) - return coveragemap_error::truncated; + return make_error(coveragemap_error::truncated); unsigned N = 0; auto ProfileNamesSize = decodeULEB128(reinterpret_cast(Data.data()), &N); if (N > Data.size()) - return coveragemap_error::malformed; + return make_error(coveragemap_error::malformed); Data = Data.substr(N); if (Data.size() < 1) - return coveragemap_error::truncated; + return make_error(coveragemap_error::truncated); N = 0; uint64_t Address = decodeULEB128(reinterpret_cast(Data.data()), &N); if (N > Data.size()) - return coveragemap_error::malformed; + return make_error(coveragemap_error::malformed); Data = Data.substr(N); if (Data.size() < ProfileNamesSize) - return coveragemap_error::malformed; - ProfileNames.create(Data.substr(0, ProfileNamesSize), Address); + return make_error(coveragemap_error::malformed); + if (Error E = ProfileNames.create(Data.substr(0, ProfileNamesSize), Address)) + return E; CoverageMapping = Data.substr(ProfileNamesSize); - return std::error_code(); + return Error::success(); } -static ErrorOr lookupSection(ObjectFile &OF, StringRef Name) { +static Expected lookupSection(ObjectFile &OF, StringRef Name) { StringRef FoundName; for (const auto &Section : OF.sections()) { if (auto EC = Section.getName(FoundName)) - return EC; + return errorCodeToError(EC); if (FoundName == Name) return Section; } - return coveragemap_error::no_data_found; + return make_error(coveragemap_error::no_data_found); } -static std::error_code -loadBinaryFormat(MemoryBufferRef ObjectBuffer, InstrProfSymtab &ProfileNames, - StringRef &CoverageMapping, uint8_t &BytesInAddress, - support::endianness &Endian, StringRef Arch) { +static Error loadBinaryFormat(MemoryBufferRef ObjectBuffer, + InstrProfSymtab &ProfileNames, + StringRef &CoverageMapping, + uint8_t &BytesInAddress, + support::endianness &Endian, StringRef Arch) { auto BinOrErr = object::createBinary(ObjectBuffer); if (!BinOrErr) - return errorToErrorCode(BinOrErr.takeError()); + return BinOrErr.takeError(); auto Bin = std::move(BinOrErr.get()); std::unique_ptr OF; if (auto *Universal = dyn_cast(Bin.get())) { // If we have a universal binary, try to look up the object for the // appropriate architecture. auto ObjectFileOrErr = Universal->getObjectForArch(Arch); - if (std::error_code EC = ObjectFileOrErr.getError()) - return EC; + if (auto EC = ObjectFileOrErr.getError()) + return errorCodeToError(EC); OF = std::move(ObjectFileOrErr.get()); } else if (isa(Bin.get())) { // For any other object file, upcast and take ownership. OF.reset(cast(Bin.release())); // If we've asked for a particular arch, make sure they match. if (!Arch.empty() && OF->getArch() != Triple(Arch).getArch()) - return object_error::arch_not_found; + return errorCodeToError(object_error::arch_not_found); } else // We can only handle object files. - return coveragemap_error::malformed; + return make_error(coveragemap_error::malformed); // The coverage uses native pointer sizes for the object it's written in. BytesInAddress = OF->getBytesInAddress(); @@ -538,23 +540,23 @@ loadBinaryFormat(MemoryBufferRef ObjectBuffer, InstrProfSymtab &ProfileNames, // Look for the sections that we are interested in. auto NamesSection = lookupSection(*OF, getInstrProfNameSectionName(false)); - if (auto EC = NamesSection.getError()) - return EC; + if (auto E = NamesSection.takeError()) + return E; auto CoverageSection = lookupSection(*OF, getInstrProfCoverageSectionName(false)); - if (auto EC = CoverageSection.getError()) - return EC; + if (auto E = CoverageSection.takeError()) + return E; // Get the contents of the given sections. - if (std::error_code EC = CoverageSection->getContents(CoverageMapping)) - return EC; - if (std::error_code EC = ProfileNames.create(*NamesSection)) - return EC; + if (auto EC = CoverageSection->getContents(CoverageMapping)) + return errorCodeToError(EC); + if (Error E = ProfileNames.create(*NamesSection)) + return E; - return std::error_code(); + return Error::success(); } -ErrorOr> +Expected> BinaryCoverageReader::create(std::unique_ptr &ObjectBuffer, StringRef Arch) { std::unique_ptr Reader(new BinaryCoverageReader()); @@ -562,44 +564,44 @@ BinaryCoverageReader::create(std::unique_ptr &ObjectBuffer, StringRef Coverage; uint8_t BytesInAddress; support::endianness Endian; - std::error_code EC; + Error E; + consumeError(std::move(E)); if (ObjectBuffer->getBuffer().startswith(TestingFormatMagic)) // This is a special format used for testing. - EC = loadTestingFormat(ObjectBuffer->getBuffer(), Reader->ProfileNames, - Coverage, BytesInAddress, Endian); + E = loadTestingFormat(ObjectBuffer->getBuffer(), Reader->ProfileNames, + Coverage, BytesInAddress, Endian); else - EC = loadBinaryFormat(ObjectBuffer->getMemBufferRef(), Reader->ProfileNames, - Coverage, BytesInAddress, Endian, Arch); - if (EC) - return EC; + E = loadBinaryFormat(ObjectBuffer->getMemBufferRef(), Reader->ProfileNames, + Coverage, BytesInAddress, Endian, Arch); + if (E) + return std::move(E); if (BytesInAddress == 4 && Endian == support::endianness::little) - EC = readCoverageMappingData( + E = readCoverageMappingData( Reader->ProfileNames, Coverage, Reader->MappingRecords, Reader->Filenames); else if (BytesInAddress == 4 && Endian == support::endianness::big) - EC = readCoverageMappingData( + E = readCoverageMappingData( Reader->ProfileNames, Coverage, Reader->MappingRecords, Reader->Filenames); else if (BytesInAddress == 8 && Endian == support::endianness::little) - EC = readCoverageMappingData( + E = readCoverageMappingData( Reader->ProfileNames, Coverage, Reader->MappingRecords, Reader->Filenames); else if (BytesInAddress == 8 && Endian == support::endianness::big) - EC = readCoverageMappingData( + E = readCoverageMappingData( Reader->ProfileNames, Coverage, Reader->MappingRecords, Reader->Filenames); else - return coveragemap_error::malformed; - if (EC) - return EC; + return make_error(coveragemap_error::malformed); + if (E) + return std::move(E); return std::move(Reader); } -std::error_code -BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) { +Error BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) { if (CurrentRecord >= MappingRecords.size()) - return coveragemap_error::eof; + return make_error(coveragemap_error::eof); FunctionsFilenames.clear(); Expressions.clear(); @@ -619,5 +621,5 @@ BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) { Record.MappingRegions = MappingRegions; ++CurrentRecord; - return std::error_code(); + return Error::success(); } diff --git a/lib/ProfileData/InstrProf.cpp b/lib/ProfileData/InstrProf.cpp index bcb31993d20..7042a5825cd 100644 --- a/lib/ProfileData/InstrProf.cpp +++ b/lib/ProfileData/InstrProf.cpp @@ -27,47 +27,50 @@ using namespace llvm; namespace { +std::string getInstrProfErrString(instrprof_error Err) { + switch (Err) { + case instrprof_error::success: + return "Success"; + case instrprof_error::eof: + return "End of File"; + case instrprof_error::unrecognized_format: + return "Unrecognized instrumentation profile encoding format"; + case instrprof_error::bad_magic: + return "Invalid instrumentation profile data (bad magic)"; + case instrprof_error::bad_header: + return "Invalid instrumentation profile data (file header is corrupt)"; + case instrprof_error::unsupported_version: + return "Unsupported instrumentation profile format version"; + case instrprof_error::unsupported_hash_type: + return "Unsupported instrumentation profile hash type"; + case instrprof_error::too_large: + return "Too much profile data"; + case instrprof_error::truncated: + return "Truncated profile data"; + case instrprof_error::malformed: + return "Malformed instrumentation profile data"; + case instrprof_error::unknown_function: + return "No profile data available for function"; + case instrprof_error::hash_mismatch: + return "Function control flow change detected (hash mismatch)"; + case instrprof_error::count_mismatch: + return "Function basic block count change detected (counter mismatch)"; + case instrprof_error::counter_overflow: + return "Counter overflow"; + case instrprof_error::value_site_count_mismatch: + return "Function value site count change detected (counter mismatch)"; + case instrprof_error::compress_failed: + return "Failed to compress data (zlib)"; + case instrprof_error::uncompress_failed: + return "Failed to uncompress data (zlib)"; + } + llvm_unreachable("A value of instrprof_error has no message."); +} + class InstrProfErrorCategoryType : public std::error_category { const char *name() const LLVM_NOEXCEPT override { return "llvm.instrprof"; } std::string message(int IE) const override { - instrprof_error E = static_cast(IE); - switch (E) { - case instrprof_error::success: - return "Success"; - case instrprof_error::eof: - return "End of File"; - case instrprof_error::unrecognized_format: - return "Unrecognized instrumentation profile encoding format"; - case instrprof_error::bad_magic: - return "Invalid instrumentation profile data (bad magic)"; - case instrprof_error::bad_header: - return "Invalid instrumentation profile data (file header is corrupt)"; - case instrprof_error::unsupported_version: - return "Unsupported instrumentation profile format version"; - case instrprof_error::unsupported_hash_type: - return "Unsupported instrumentation profile hash type"; - case instrprof_error::too_large: - return "Too much profile data"; - case instrprof_error::truncated: - return "Truncated profile data"; - case instrprof_error::malformed: - return "Malformed instrumentation profile data"; - case instrprof_error::unknown_function: - return "No profile data available for function"; - case instrprof_error::hash_mismatch: - return "Function control flow change detected (hash mismatch)"; - case instrprof_error::count_mismatch: - return "Function basic block count change detected (counter mismatch)"; - case instrprof_error::counter_overflow: - return "Counter overflow"; - case instrprof_error::value_site_count_mismatch: - return "Function value site count change detected (counter mismatch)"; - case instrprof_error::compress_failed: - return "Failed to compress data (zlib)"; - case instrprof_error::uncompress_failed: - return "Failed to uncompress data (zlib)"; - } - llvm_unreachable("A value of instrprof_error has no message."); + return getInstrProfErrString(static_cast(IE)); } }; } // end anonymous namespace @@ -105,6 +108,12 @@ void SoftInstrProfErrors::addError(instrprof_error IE) { } } +std::string InstrProfError::message() const { + return getInstrProfErrString(Err); +} + +template <> char ProfErrorInfoBase::ID = 0; + std::string getPGOFuncName(StringRef RawFuncName, GlobalValue::LinkageTypes Linkage, StringRef FileName, @@ -214,9 +223,8 @@ void InstrProfSymtab::create(Module &M, bool InLTO) { finalizeSymtab(); } -std::error_code -collectPGOFuncNameStrings(const std::vector &NameStrs, - bool doCompression, std::string &Result) { +Error collectPGOFuncNameStrings(const std::vector &NameStrs, + bool doCompression, std::string &Result) { assert(NameStrs.size() && "No name data to emit"); uint8_t Header[16], *P = Header; @@ -238,11 +246,12 @@ collectPGOFuncNameStrings(const std::vector &NameStrs, unsigned HeaderLen = P - &Header[0]; Result.append(HeaderStr, HeaderLen); Result += InputStr; - return make_error_code(instrprof_error::success); + return Error::success(); }; - if (!doCompression) + if (!doCompression) { return WriteStringToResult(0, UncompressedNameStrings); + } SmallVector CompressedNameStrings; zlib::Status Success = @@ -250,7 +259,7 @@ collectPGOFuncNameStrings(const std::vector &NameStrs, zlib::BestSizeCompression); if (Success != zlib::StatusOK) - return make_error_code(instrprof_error::compress_failed); + return make_error(instrprof_error::compress_failed); return WriteStringToResult( CompressedNameStrings.size(), @@ -264,9 +273,8 @@ StringRef getPGOFuncNameVarInitializer(GlobalVariable *NameVar) { return NameStr; } -std::error_code -collectPGOFuncNameStrings(const std::vector &NameVars, - std::string &Result, bool doCompression) { +Error collectPGOFuncNameStrings(const std::vector &NameVars, + std::string &Result, bool doCompression) { std::vector NameStrs; for (auto *NameVar : NameVars) { NameStrs.push_back(getPGOFuncNameVarInitializer(NameVar)); @@ -275,8 +283,7 @@ collectPGOFuncNameStrings(const std::vector &NameVars, NameStrs, zlib::isAvailable() && doCompression, Result); } -std::error_code readPGOFuncNameStrings(StringRef NameStrings, - InstrProfSymtab &Symtab) { +Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab) { const uint8_t *P = reinterpret_cast(NameStrings.data()); const uint8_t *EndP = reinterpret_cast(NameStrings.data() + NameStrings.size()); @@ -294,7 +301,7 @@ std::error_code readPGOFuncNameStrings(StringRef NameStrings, CompressedSize); if (zlib::uncompress(CompressedNameStrings, UncompressedNameStrings, UncompressedSize) != zlib::StatusOK) - return make_error_code(instrprof_error::uncompress_failed); + return make_error(instrprof_error::uncompress_failed); P += CompressedSize; NameStrings = StringRef(UncompressedNameStrings.data(), UncompressedNameStrings.size()); @@ -313,7 +320,7 @@ std::error_code readPGOFuncNameStrings(StringRef NameStrings, P++; } Symtab.finalizeSymtab(); - return make_error_code(instrprof_error::success); + return Error::success(); } void InstrProfValueSiteRecord::merge(SoftInstrProfErrors &SIPE, @@ -577,45 +584,45 @@ static std::unique_ptr allocValueProfData(uint32_t TotalSize) { ValueProfData()); } -instrprof_error ValueProfData::checkIntegrity() { +Error ValueProfData::checkIntegrity() { if (NumValueKinds > IPVK_Last + 1) - return instrprof_error::malformed; + return make_error(instrprof_error::malformed); // Total size needs to be mulltiple of quadword size. if (TotalSize % sizeof(uint64_t)) - return instrprof_error::malformed; + return make_error(instrprof_error::malformed); ValueProfRecord *VR = getFirstValueProfRecord(this); for (uint32_t K = 0; K < this->NumValueKinds; K++) { if (VR->Kind > IPVK_Last) - return instrprof_error::malformed; + return make_error(instrprof_error::malformed); VR = getValueProfRecordNext(VR); if ((char *)VR - (char *)this > (ptrdiff_t)TotalSize) - return instrprof_error::malformed; + return make_error(instrprof_error::malformed); } - return instrprof_error::success; + return Error::success(); } -ErrorOr> +Expected> ValueProfData::getValueProfData(const unsigned char *D, const unsigned char *const BufferEnd, support::endianness Endianness) { using namespace support; if (D + sizeof(ValueProfData) > BufferEnd) - return instrprof_error::truncated; + return make_error(instrprof_error::truncated); const unsigned char *Header = D; uint32_t TotalSize = swapToHostOrder(Header, Endianness); if (D + TotalSize > BufferEnd) - return instrprof_error::too_large; + return make_error(instrprof_error::too_large); std::unique_ptr VPD = allocValueProfData(TotalSize); memcpy(VPD.get(), D, TotalSize); // Byte swap. VPD->swapBytesToHost(Endianness); - instrprof_error EC = VPD->checkIntegrity(); - if (EC != instrprof_error::success) - return EC; + Error E = VPD->checkIntegrity(); + if (E) + return std::move(E); return std::move(VPD); } diff --git a/lib/ProfileData/InstrProfReader.cpp b/lib/ProfileData/InstrProfReader.cpp index 0828bb2c3fc..2678ac28561 100644 --- a/lib/ProfileData/InstrProfReader.cpp +++ b/lib/ProfileData/InstrProfReader.cpp @@ -18,33 +18,33 @@ using namespace llvm; -static ErrorOr> +static Expected> setupMemoryBuffer(std::string Path) { ErrorOr> BufferOrErr = MemoryBuffer::getFileOrSTDIN(Path); if (std::error_code EC = BufferOrErr.getError()) - return EC; + return errorCodeToError(EC); return std::move(BufferOrErr.get()); } -static std::error_code initializeReader(InstrProfReader &Reader) { +static Error initializeReader(InstrProfReader &Reader) { return Reader.readHeader(); } -ErrorOr> +Expected> InstrProfReader::create(std::string Path) { // Set up the buffer to read. auto BufferOrError = setupMemoryBuffer(Path); - if (std::error_code EC = BufferOrError.getError()) - return EC; + if (Error E = BufferOrError.takeError()) + return std::move(E); return InstrProfReader::create(std::move(BufferOrError.get())); } -ErrorOr> +Expected> InstrProfReader::create(std::unique_ptr Buffer) { // Sanity check the buffer. if (Buffer->getBufferSize() > std::numeric_limits::max()) - return instrprof_error::too_large; + return make_error(instrprof_error::too_large); std::unique_ptr Result; // Create the reader. @@ -57,46 +57,49 @@ InstrProfReader::create(std::unique_ptr Buffer) { else if (TextInstrProfReader::hasFormat(*Buffer)) Result.reset(new TextInstrProfReader(std::move(Buffer))); else - return instrprof_error::unrecognized_format; + return make_error(instrprof_error::unrecognized_format); // Initialize the reader and return the result. - if (std::error_code EC = initializeReader(*Result)) - return EC; + if (Error E = initializeReader(*Result)) + return std::move(E); return std::move(Result); } -ErrorOr> +Expected> IndexedInstrProfReader::create(std::string Path) { // Set up the buffer to read. auto BufferOrError = setupMemoryBuffer(Path); - if (std::error_code EC = BufferOrError.getError()) - return EC; + if (Error E = BufferOrError.takeError()) + return std::move(E); return IndexedInstrProfReader::create(std::move(BufferOrError.get())); } -ErrorOr> +Expected> IndexedInstrProfReader::create(std::unique_ptr Buffer) { // Sanity check the buffer. if (Buffer->getBufferSize() > std::numeric_limits::max()) - return instrprof_error::too_large; + return make_error(instrprof_error::too_large); // Create the reader. if (!IndexedInstrProfReader::hasFormat(*Buffer)) - return instrprof_error::bad_magic; + return make_error(instrprof_error::bad_magic); auto Result = llvm::make_unique(std::move(Buffer)); // Initialize the reader and return the result. - if (std::error_code EC = initializeReader(*Result)) - return EC; + if (Error E = initializeReader(*Result)) + return std::move(E); return std::move(Result); } void InstrProfIterator::Increment() { - if (Reader->readNextRecord(Record)) + if (auto E = Reader->readNextRecord(Record)) { + // Handle errors in the reader. + InstrProfError::take(std::move(E)); *this = InstrProfIterator(); + } } bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) { @@ -112,7 +115,7 @@ bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) { // Read the profile variant flag from the header: ":FE" means this is a FE // generated profile. ":IR" means this is an IR level profile. Other strings // with a leading ':' will be reported an error format. -std::error_code TextInstrProfReader::readHeader() { +Error TextInstrProfReader::readHeader() { Symtab.reset(new InstrProfSymtab()); bool IsIRInstr = false; if (!Line->startswith(":")) { @@ -125,14 +128,14 @@ std::error_code TextInstrProfReader::readHeader() { else if (Str.equals_lower("fe")) IsIRInstr = false; else - return instrprof_error::bad_header; + return error(instrprof_error::bad_header); ++Line; IsIRLevelProfile = IsIRInstr; return success(); } -std::error_code +Error TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) { #define CHECK_LINE_END(Line) \ @@ -196,7 +199,7 @@ TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) { #undef VP_READ_ADVANCE } -std::error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) { +Error TextInstrProfReader::readNextRecord(InstrProfRecord &Record) { // Skip empty lines and comments. while (!Line.is_at_end() && (Line->empty() || Line->startswith("#"))) ++Line; @@ -238,8 +241,8 @@ std::error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) { } // Check if value profile data exists and read it if so. - if (std::error_code EC = readValueProfileData(Record)) - return EC; + if (Error E = readValueProfileData(Record)) + return E; // This is needed to avoid two pass parsing because llvm-profdata // does dumping while reading. @@ -258,7 +261,7 @@ bool RawInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) { } template -std::error_code RawInstrProfReader::readHeader() { +Error RawInstrProfReader::readHeader() { if (!hasFormat(*DataBuffer)) return error(instrprof_error::bad_magic); if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header)) @@ -270,26 +273,25 @@ std::error_code RawInstrProfReader::readHeader() { } template -std::error_code -RawInstrProfReader::readNextHeader(const char *CurrentPos) { +Error RawInstrProfReader::readNextHeader(const char *CurrentPos) { const char *End = DataBuffer->getBufferEnd(); // Skip zero padding between profiles. while (CurrentPos != End && *CurrentPos == 0) ++CurrentPos; // If there's nothing left, we're done. if (CurrentPos == End) - return instrprof_error::eof; + return make_error(instrprof_error::eof); // If there isn't enough space for another header, this is probably just // garbage at the end of the file. if (CurrentPos + sizeof(RawInstrProf::Header) > End) - return instrprof_error::malformed; + return make_error(instrprof_error::malformed); // The writer ensures each profile is padded to start at an aligned address. if (reinterpret_cast(CurrentPos) % alignOf()) - return instrprof_error::malformed; + return make_error(instrprof_error::malformed); // The magic should have the same byte order as in the previous header. uint64_t Magic = *reinterpret_cast(CurrentPos); if (Magic != swap(RawInstrProf::getMagic())) - return instrprof_error::bad_magic; + return make_error(instrprof_error::bad_magic); // There's another profile to read, so we need to process the header. auto *Header = reinterpret_cast(CurrentPos); @@ -297,11 +299,9 @@ RawInstrProfReader::readNextHeader(const char *CurrentPos) { } template -std::error_code -RawInstrProfReader::createSymtab(InstrProfSymtab &Symtab) { - std::error_code EC = Symtab.create(StringRef(NamesStart, NamesSize)); - if (EC) - return EC; +Error RawInstrProfReader::createSymtab(InstrProfSymtab &Symtab) { + if (Error E = Symtab.create(StringRef(NamesStart, NamesSize))) + return error(std::move(E)); for (const RawInstrProf::ProfileData *I = Data; I != DataEnd; ++I) { const IntPtrT FPtr = swap(I->FunctionPointer); if (!FPtr) @@ -313,8 +313,8 @@ RawInstrProfReader::createSymtab(InstrProfSymtab &Symtab) { } template -std::error_code -RawInstrProfReader::readHeader(const RawInstrProf::Header &Header) { +Error RawInstrProfReader::readHeader( + const RawInstrProf::Header &Header) { Version = swap(Header.Version); if (GET_VERSION(Version) != RawInstrProf::Version) return error(instrprof_error::unsupported_version); @@ -346,28 +346,27 @@ RawInstrProfReader::readHeader(const RawInstrProf::Header &Header) { ValueDataStart = reinterpret_cast(Start + ValueDataOffset); std::unique_ptr NewSymtab = make_unique(); - if (auto EC = createSymtab(*NewSymtab.get())) - return EC; + if (Error E = createSymtab(*NewSymtab.get())) + return E; Symtab = std::move(NewSymtab); return success(); } template -std::error_code RawInstrProfReader::readName(InstrProfRecord &Record) { +Error RawInstrProfReader::readName(InstrProfRecord &Record) { Record.Name = getName(Data->NameRef); return success(); } template -std::error_code RawInstrProfReader::readFuncHash( - InstrProfRecord &Record) { +Error RawInstrProfReader::readFuncHash(InstrProfRecord &Record) { Record.Hash = swap(Data->FuncHash); return success(); } template -std::error_code RawInstrProfReader::readRawCounts( +Error RawInstrProfReader::readRawCounts( InstrProfRecord &Record) { uint32_t NumCounters = swap(Data->NumCounters); IntPtrT CounterPtr = Data->CounterPtr; @@ -394,8 +393,8 @@ std::error_code RawInstrProfReader::readRawCounts( } template -std::error_code -RawInstrProfReader::readValueProfilingData(InstrProfRecord &Record) { +Error RawInstrProfReader::readValueProfilingData( + InstrProfRecord &Record) { Record.clearValueData(); CurValueDataSize = 0; @@ -407,13 +406,13 @@ RawInstrProfReader::readValueProfilingData(InstrProfRecord &Record) { if (!NumValueKinds) return success(); - ErrorOr> VDataPtrOrErr = + Expected> VDataPtrOrErr = ValueProfData::getValueProfData( ValueDataStart, (const unsigned char *)DataBuffer->getBufferEnd(), getDataEndianness()); - if (VDataPtrOrErr.getError()) - return VDataPtrOrErr.getError(); + if (Error E = VDataPtrOrErr.takeError()) + return E; // Note that besides deserialization, this also performs the conversion for // indirect call targets. The function pointers from the raw profile are @@ -424,28 +423,27 @@ RawInstrProfReader::readValueProfilingData(InstrProfRecord &Record) { } template -std::error_code -RawInstrProfReader::readNextRecord(InstrProfRecord &Record) { +Error RawInstrProfReader::readNextRecord(InstrProfRecord &Record) { if (atEnd()) // At this point, ValueDataStart field points to the next header. - if (std::error_code EC = readNextHeader(getNextHeaderPos())) - return EC; + if (Error E = readNextHeader(getNextHeaderPos())) + return E; // Read name ad set it in Record. - if (std::error_code EC = readName(Record)) - return EC; + if (Error E = readName(Record)) + return E; // Read FuncHash and set it in Record. - if (std::error_code EC = readFuncHash(Record)) - return EC; + if (Error E = readFuncHash(Record)) + return E; // Read raw counts and set Record. - if (std::error_code EC = readRawCounts(Record)) - return EC; + if (Error E = readRawCounts(Record)) + return E; // Read value data and set Record. - if (std::error_code EC = readValueProfilingData(Record)) - return EC; + if (Error E = readValueProfilingData(Record)) + return E; // Iterate. advanceData(); @@ -467,10 +465,10 @@ typedef InstrProfLookupTrait::offset_type offset_type; bool InstrProfLookupTrait::readValueProfilingData( const unsigned char *&D, const unsigned char *const End) { - ErrorOr> VDataPtrOrErr = + Expected> VDataPtrOrErr = ValueProfData::getValueProfData(D, End, ValueProfDataEndianness); - if (VDataPtrOrErr.getError()) + if (VDataPtrOrErr.takeError()) return false; VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr); @@ -526,31 +524,31 @@ data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D, } template -std::error_code InstrProfReaderIndex::getRecords( +Error InstrProfReaderIndex::getRecords( StringRef FuncName, ArrayRef &Data) { auto Iter = HashTable->find(FuncName); if (Iter == HashTable->end()) - return instrprof_error::unknown_function; + return make_error(instrprof_error::unknown_function); Data = (*Iter); if (Data.empty()) - return instrprof_error::malformed; + return make_error(instrprof_error::malformed); - return instrprof_error::success; + return Error::success(); } template -std::error_code InstrProfReaderIndex::getRecords( +Error InstrProfReaderIndex::getRecords( ArrayRef &Data) { if (atEnd()) - return instrprof_error::eof; + return make_error(instrprof_error::eof); Data = *RecordIterator; if (Data.empty()) - return instrprof_error::malformed; + return make_error(instrprof_error::malformed); - return instrprof_error::success; + return Error::success(); } template @@ -609,7 +607,7 @@ IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version, } } -std::error_code IndexedInstrProfReader::readHeader() { +Error IndexedInstrProfReader::readHeader() { const unsigned char *Start = (const unsigned char *)DataBuffer->getBufferStart(); const unsigned char *Cur = Start; @@ -661,13 +659,13 @@ InstrProfSymtab &IndexedInstrProfReader::getSymtab() { return *Symtab.get(); } -ErrorOr +Expected IndexedInstrProfReader::getInstrProfRecord(StringRef FuncName, uint64_t FuncHash) { ArrayRef Data; - std::error_code EC = Index->getRecords(FuncName, Data); - if (EC != instrprof_error::success) - return EC; + Error Err = Index->getRecords(FuncName, Data); + if (Err) + return std::move(Err); // Found it. Look for counters with the right hash. for (unsigned I = 0, E = Data.size(); I < E; ++I) { // Check for a match and fill the vector if there is one. @@ -678,26 +676,25 @@ IndexedInstrProfReader::getInstrProfRecord(StringRef FuncName, return error(instrprof_error::hash_mismatch); } -std::error_code -IndexedInstrProfReader::getFunctionCounts(StringRef FuncName, uint64_t FuncHash, - std::vector &Counts) { - ErrorOr Record = getInstrProfRecord(FuncName, FuncHash); - if (std::error_code EC = Record.getError()) - return EC; +Error IndexedInstrProfReader::getFunctionCounts(StringRef FuncName, + uint64_t FuncHash, + std::vector &Counts) { + Expected Record = getInstrProfRecord(FuncName, FuncHash); + if (Error E = Record.takeError()) + return error(std::move(E)); Counts = Record.get().Counts; return success(); } -std::error_code IndexedInstrProfReader::readNextRecord( - InstrProfRecord &Record) { +Error IndexedInstrProfReader::readNextRecord(InstrProfRecord &Record) { static unsigned RecordIndex = 0; ArrayRef Data; - std::error_code EC = Index->getRecords(Data); - if (EC != instrprof_error::success) - return error(EC); + Error E = Index->getRecords(Data); + if (E) + return error(std::move(E)); Record = Data[RecordIndex++]; if (RecordIndex >= Data.size()) { diff --git a/lib/ProfileData/InstrProfWriter.cpp b/lib/ProfileData/InstrProfWriter.cpp index d6caca2a7a9..9b01dac313b 100644 --- a/lib/ProfileData/InstrProfWriter.cpp +++ b/lib/ProfileData/InstrProfWriter.cpp @@ -156,8 +156,7 @@ void InstrProfWriter::setOutputSparse(bool Sparse) { this->Sparse = Sparse; } -std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I, - uint64_t Weight) { +Error InstrProfWriter::addRecord(InstrProfRecord &&I, uint64_t Weight) { auto &ProfileDataMap = FunctionData[I.Name]; bool NewFunc; @@ -180,7 +179,7 @@ std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I, Dest.sortValueData(); - return Dest.getError(); + return Dest.takeError(); } bool InstrProfWriter::shouldEncodeData(const ProfilingData &PD) { diff --git a/lib/Transforms/Instrumentation/InstrProfiling.cpp b/lib/Transforms/Instrumentation/InstrProfiling.cpp index 930001fd684..11369d6f70d 100644 --- a/lib/Transforms/Instrumentation/InstrProfiling.cpp +++ b/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -374,9 +374,9 @@ void InstrProfiling::emitNameData() { return; std::string CompressedNameStr; - if (auto EC = collectPGOFuncNameStrings(ReferencedNames, CompressedNameStr, + if (Error E = collectPGOFuncNameStrings(ReferencedNames, CompressedNameStr, DoNameCompression)) { - llvm::report_fatal_error(EC.message(), false); + llvm::report_fatal_error(toString(std::move(E)), false); } auto &Ctx = M->getContext(); diff --git a/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/lib/Transforms/Instrumentation/PGOInstrumentation.cpp index 379f7c5ebed..835f75edcd2 100644 --- a/lib/Transforms/Instrumentation/PGOInstrumentation.cpp +++ b/lib/Transforms/Instrumentation/PGOInstrumentation.cpp @@ -582,23 +582,28 @@ void PGOUseFunc::setEdgeCount(DirectEdges &Edges, uint64_t Value) { // Return true if the profile are successfully read, and false on errors. bool PGOUseFunc::readCounters(IndexedInstrProfReader *PGOReader) { auto &Ctx = M->getContext(); - ErrorOr Result = + Expected Result = PGOReader->getInstrProfRecord(FuncInfo.FuncName, FuncInfo.FunctionHash); - if (std::error_code EC = Result.getError()) { - if (EC == instrprof_error::unknown_function) { - NumOfPGOMissing++; - if (NoPGOWarnMissing) - return false; - } else if (EC == instrprof_error::hash_mismatch || - EC == llvm::instrprof_error::malformed) { - NumOfPGOMismatch++; - if (NoPGOWarnMismatch) - return false; - } + if (Error E = Result.takeError()) { + handleAllErrors(std::move(E), [&](const InstrProfError &IPE) { + auto Err = IPE.get(); + bool SkipWarning = false; + if (Err == instrprof_error::unknown_function) { + NumOfPGOMissing++; + SkipWarning = NoPGOWarnMissing; + } else if (Err == instrprof_error::hash_mismatch || + Err == instrprof_error::malformed) { + NumOfPGOMismatch++; + SkipWarning = NoPGOWarnMismatch; + } - std::string Msg = EC.message() + std::string(" ") + F.getName().str(); - Ctx.diagnose( - DiagnosticInfoPGOProfile(M->getName().data(), Msg, DS_Warning)); + if (SkipWarning) + return; + + std::string Msg = IPE.message() + std::string(" ") + F.getName().str(); + Ctx.diagnose( + DiagnosticInfoPGOProfile(M->getName().data(), Msg, DS_Warning)); + }); return false; } ProfileRecord = std::move(Result.get()); @@ -854,9 +859,11 @@ static bool annotateAllFunctions( auto &Ctx = M.getContext(); // Read the counter array from file. auto ReaderOrErr = IndexedInstrProfReader::create(ProfileFileName); - if (std::error_code EC = ReaderOrErr.getError()) { - Ctx.diagnose( - DiagnosticInfoPGOProfile(ProfileFileName.data(), EC.message())); + if (Error E = ReaderOrErr.takeError()) { + handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) { + Ctx.diagnose( + DiagnosticInfoPGOProfile(ProfileFileName.data(), EI.message())); + }); return false; } diff --git a/tools/llvm-cov/CodeCoverage.cpp b/tools/llvm-cov/CodeCoverage.cpp index 1c11fe60197..cd786edc25d 100644 --- a/tools/llvm-cov/CodeCoverage.cpp +++ b/tools/llvm-cov/CodeCoverage.cpp @@ -210,10 +210,9 @@ std::unique_ptr CodeCoverageTool::load() { errs() << "warning: profile data may be out of date - object is newer\n"; auto CoverageOrErr = CoverageMapping::load(ObjectFilename, PGOFilename, CoverageArch); - if (std::error_code EC = CoverageOrErr.getError()) { + if (Error E = CoverageOrErr.takeError()) { colored_ostream(errs(), raw_ostream::RED) - << "error: Failed to load coverage: " << EC.message(); - errs() << "\n"; + << "error: Failed to load coverage: " << toString(std::move(E)) << "\n"; return nullptr; } auto Coverage = std::move(CoverageOrErr.get()); diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp index 5cdf962e885..d45e6afa5a5 100644 --- a/tools/llvm-profdata/llvm-profdata.cpp +++ b/tools/llvm-profdata/llvm-profdata.cpp @@ -47,38 +47,50 @@ static void exitWithError(const Twine &Message, StringRef Whence = "", ::exit(1); } -static void exitWithErrorCode(const std::error_code &Error, - StringRef Whence = "") { - if (Error.category() == instrprof_category()) { - instrprof_error instrError = static_cast(Error.value()); - if (instrError == instrprof_error::unrecognized_format) { - // Hint for common error of forgetting -sample for sample profiles. - exitWithError(Error.message(), Whence, - "Perhaps you forgot to use the -sample option?"); - } +static void exitWithError(Error E, StringRef Whence = "") { + if (E.isA()) { + handleAllErrors(std::move(E), [&](const InstrProfError &IPE) { + instrprof_error instrError = IPE.get(); + StringRef Hint = ""; + if (instrError == instrprof_error::unrecognized_format) { + // Hint for common error of forgetting -sample for sample profiles. + Hint = "Perhaps you forgot to use the -sample option?"; + } + exitWithError(IPE.message(), Whence, Hint); + }); } - exitWithError(Error.message(), Whence); + + exitWithError(toString(std::move(E)), Whence); +} + +static void exitWithErrorCode(std::error_code EC, StringRef Whence = "") { + exitWithError(EC.message(), Whence); } namespace { enum ProfileKinds { instr, sample }; } -static void handleMergeWriterError(std::error_code &Error, - StringRef WhenceFile = "", +static void handleMergeWriterError(Error E, StringRef WhenceFile = "", StringRef WhenceFunction = "", bool ShowHint = true) { if (!WhenceFile.empty()) errs() << WhenceFile << ": "; if (!WhenceFunction.empty()) errs() << WhenceFunction << ": "; - errs() << Error.message() << "\n"; + + auto IPE = instrprof_error::success; + E = handleErrors(std::move(E), + [&IPE](std::unique_ptr E) -> Error { + IPE = E->get(); + return Error(std::move(E)); + }); + errs() << toString(std::move(E)) << "\n"; if (ShowHint) { StringRef Hint = ""; - if (Error.category() == instrprof_category()) { - instrprof_error instrError = static_cast(Error.value()); - switch (instrError) { + if (IPE != instrprof_error::success) { + switch (IPE) { case instrprof_error::hash_mismatch: case instrprof_error::count_mismatch: case instrprof_error::value_site_count_mismatch: @@ -120,11 +132,11 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs, exitWithErrorCode(EC, OutputFilename); InstrProfWriter Writer(OutputSparse); - SmallSet WriterErrorCodes; + SmallSet WriterErrorCodes; for (const auto &Input : Inputs) { auto ReaderOrErr = InstrProfReader::create(Input.Filename); - if (std::error_code ec = ReaderOrErr.getError()) - exitWithErrorCode(ec, Input.Filename); + if (Error E = ReaderOrErr.takeError()) + exitWithError(std::move(E), Input.Filename); auto Reader = std::move(ReaderOrErr.get()); bool IsIRProfile = Reader->isIRLevelProfile(); @@ -132,14 +144,16 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs, exitWithError("Merge IR generated profile with Clang generated profile."); for (auto &I : *Reader) { - if (std::error_code EC = Writer.addRecord(std::move(I), Input.Weight)) { + if (Error E = Writer.addRecord(std::move(I), Input.Weight)) { // Only show hint the first time an error occurs. - bool firstTime = WriterErrorCodes.insert(EC).second; - handleMergeWriterError(EC, Input.Filename, I.Name, firstTime); + instrprof_error IPE = InstrProfError::take(std::move(E)); + bool firstTime = WriterErrorCodes.insert(IPE).second; + handleMergeWriterError(make_error(IPE), Input.Filename, + I.Name, firstTime); } } if (Reader->hasError()) - exitWithErrorCode(Reader->getError(), Input.Filename); + exitWithError(Reader->getError(), Input.Filename); } if (OutputFormat == PF_Text) Writer.writeText(Output); @@ -187,7 +201,7 @@ static void mergeSampleProfile(const WeightedFileVector &Inputs, sampleprof_error Result = ProfileMap[FName].merge(Samples, Input.Weight); if (Result != sampleprof_error::success) { std::error_code EC = make_error_code(Result); - handleMergeWriterError(EC, Input.Filename, FName); + handleMergeWriterError(errorCodeToError(EC), Input.Filename, FName); } } } @@ -268,8 +282,8 @@ static int showInstrProfile(std::string Filename, bool ShowCounts, Cutoffs = {800000, 900000, 950000, 990000, 999000, 999900, 999990}; } InstrProfSummary PS(Cutoffs); - if (std::error_code EC = ReaderOrErr.getError()) - exitWithErrorCode(EC, Filename); + if (Error E = ReaderOrErr.takeError()) + exitWithError(std::move(E), Filename); auto Reader = std::move(ReaderOrErr.get()); bool IsIRInstr = Reader->isIRLevelProfile(); @@ -335,7 +349,7 @@ static int showInstrProfile(std::string Filename, bool ShowCounts, } if (Reader->hasError()) - exitWithErrorCode(Reader->getError(), Filename); + exitWithError(Reader->getError(), Filename); if (ShowCounts && TextFormat) return 0; diff --git a/unittests/ProfileData/CoverageMappingTest.cpp b/unittests/ProfileData/CoverageMappingTest.cpp index 81e9cb13233..53b40ebae85 100644 --- a/unittests/ProfileData/CoverageMappingTest.cpp +++ b/unittests/ProfileData/CoverageMappingTest.cpp @@ -20,11 +20,11 @@ using namespace llvm; using namespace coverage; -static ::testing::AssertionResult NoError(std::error_code EC) { - if (!EC) +static ::testing::AssertionResult NoError(Error E) { + if (!E) return ::testing::AssertionSuccess(); - return ::testing::AssertionFailure() << "error " << EC.value() - << ": " << EC.message(); + return ::testing::AssertionFailure() << "error: " << toString(std::move(E)) + << "\n"; } namespace llvm { @@ -70,14 +70,14 @@ struct CoverageMappingReaderMock : CoverageMappingReader { CoverageMappingReaderMock(ArrayRef Functions) : Functions(Functions) {} - std::error_code readNextRecord(CoverageMappingRecord &Record) override { + Error readNextRecord(CoverageMappingRecord &Record) override { if (Functions.empty()) - return coveragemap_error::eof; + return make_error(coveragemap_error::eof); Functions.front().fillCoverageMappingRecord(Record); Functions = Functions.slice(1); - return coveragemap_error::success; + return Error::success(); } }; @@ -190,7 +190,7 @@ struct CoverageMappingTest : ::testing::Test { void readProfCounts() { auto Profile = ProfileWriter.writeBuffer(); auto ReaderOrErr = IndexedInstrProfReader::create(std::move(Profile)); - ASSERT_TRUE(NoError(ReaderOrErr.getError())); + ASSERT_TRUE(NoError(ReaderOrErr.takeError())); ProfileReader = std::move(ReaderOrErr.get()); } @@ -200,7 +200,7 @@ struct CoverageMappingTest : ::testing::Test { CoverageMappingReaderMock CovReader(OutputFunctions); auto CoverageOrErr = CoverageMapping::load(CovReader, *ProfileReader); - ASSERT_TRUE(NoError(CoverageOrErr.getError())); + ASSERT_TRUE(NoError(CoverageOrErr.takeError())); LoadedCoverage = std::move(CoverageOrErr.get()); } }; diff --git a/unittests/ProfileData/InstrProfTest.cpp b/unittests/ProfileData/InstrProfTest.cpp index 2d9a2218e55..9ef3487ba18 100644 --- a/unittests/ProfileData/InstrProfTest.cpp +++ b/unittests/ProfileData/InstrProfTest.cpp @@ -19,19 +19,24 @@ using namespace llvm; -static ::testing::AssertionResult NoError(std::error_code EC) { - if (!EC) +static ::testing::AssertionResult NoError(Error E) { + if (!E) return ::testing::AssertionSuccess(); - return ::testing::AssertionFailure() << "error " << EC.value() - << ": " << EC.message(); + return ::testing::AssertionFailure() << "error: " << toString(std::move(E)) + << "\n"; } -static ::testing::AssertionResult ErrorEquals(std::error_code Expected, - std::error_code Found) { +static ::testing::AssertionResult ErrorEquals(instrprof_error Expected, + Error E) { + instrprof_error Found; + std::string FoundMsg; + handleAllErrors(std::move(E), [&](const InstrProfError &IPE) { + Found = IPE.get(); + FoundMsg = IPE.message(); + }); if (Expected == Found) return ::testing::AssertionSuccess(); - return ::testing::AssertionFailure() << "error " << Found.value() - << ": " << Found.message(); + return ::testing::AssertionFailure() << "error: " << FoundMsg << "\n"; } namespace { @@ -44,7 +49,7 @@ struct InstrProfTest : ::testing::Test { void readProfile(std::unique_ptr Profile) { auto ReaderOrErr = IndexedInstrProfReader::create(std::move(Profile)); - ASSERT_TRUE(NoError(ReaderOrErr.getError())); + ASSERT_TRUE(NoError(ReaderOrErr.takeError())); Reader = std::move(ReaderOrErr.get()); } }; @@ -90,23 +95,23 @@ TEST_P(MaybeSparseInstrProfTest, get_instr_prof_record) { auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); - ErrorOr R = Reader->getInstrProfRecord("foo", 0x1234); - ASSERT_TRUE(NoError(R.getError())); + Expected R = Reader->getInstrProfRecord("foo", 0x1234); + ASSERT_TRUE(NoError(R.takeError())); ASSERT_EQ(2U, R->Counts.size()); ASSERT_EQ(1U, R->Counts[0]); ASSERT_EQ(2U, R->Counts[1]); R = Reader->getInstrProfRecord("foo", 0x1235); - ASSERT_TRUE(NoError(R.getError())); + ASSERT_TRUE(NoError(R.takeError())); ASSERT_EQ(2U, R->Counts.size()); ASSERT_EQ(3U, R->Counts[0]); ASSERT_EQ(4U, R->Counts[1]); R = Reader->getInstrProfRecord("foo", 0x5678); - ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, R.getError())); + ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, R.takeError())); R = Reader->getInstrProfRecord("bar", 0x1234); - ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, R.getError())); + ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, R.takeError())); } TEST_P(MaybeSparseInstrProfTest, get_function_counts) { @@ -128,12 +133,11 @@ TEST_P(MaybeSparseInstrProfTest, get_function_counts) { ASSERT_EQ(3U, Counts[0]); ASSERT_EQ(4U, Counts[1]); - std::error_code EC; - EC = Reader->getFunctionCounts("foo", 0x5678, Counts); - ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, EC)); + Error E1 = Reader->getFunctionCounts("foo", 0x5678, Counts); + ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, std::move(E1))); - EC = Reader->getFunctionCounts("bar", 0x1234, Counts); - ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, EC)); + Error E2 = Reader->getFunctionCounts("bar", 0x1234, Counts); + ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, std::move(E2))); } // Profile data is copied from general.proftext @@ -235,8 +239,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write) { auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); - ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.getError())); + Expected R = Reader->getInstrProfRecord("caller", 0x1234); + ASSERT_TRUE(NoError(R.takeError())); ASSERT_EQ(4U, R->getNumValueSites(IPVK_IndirectCallTarget)); ASSERT_EQ(3U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0)); ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1)); @@ -266,8 +270,8 @@ TEST_P(MaybeSparseInstrProfTest, annotate_vp_data) { NoError(Writer.addRecord(std::move(Record))); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); - ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.getError())); + Expected R = Reader->getInstrProfRecord("caller", 0x1234); + ASSERT_TRUE(NoError(R.takeError())); LLVMContext Ctx; std::unique_ptr M(new Module("MyModule", Ctx)); @@ -378,8 +382,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_with_weight) { auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); - ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.getError())); + Expected R = Reader->getInstrProfRecord("caller", 0x1234); + ASSERT_TRUE(NoError(R.takeError())); ASSERT_EQ(4U, R->getNumValueSites(IPVK_IndirectCallTarget)); ASSERT_EQ(3U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0)); ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1)); @@ -431,8 +435,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_big_endian) { // Set big endian input. Reader->setValueProfDataEndianness(support::big); - ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.getError())); + Expected R = Reader->getInstrProfRecord("caller", 0x1234); + ASSERT_TRUE(NoError(R.takeError())); ASSERT_EQ(4U, R->getNumValueSites(IPVK_IndirectCallTarget)); ASSERT_EQ(3U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0)); ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1)); @@ -513,8 +517,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1) { auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); - ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.getError())); + Expected R = Reader->getInstrProfRecord("caller", 0x1234); + ASSERT_TRUE(NoError(R.takeError())); ASSERT_EQ(5U, R->getNumValueSites(IPVK_IndirectCallTarget)); ASSERT_EQ(4U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0)); ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1)); @@ -566,23 +570,27 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1_saturation) { InstrProfRecord Record1("foo", 0x1234, {1}); auto Result1 = Writer.addRecord(std::move(Record1)); - ASSERT_EQ(Result1, instrprof_error::success); + ASSERT_EQ(InstrProfError::take(std::move(Result1)), + instrprof_error::success); // Verify counter overflow. InstrProfRecord Record2("foo", 0x1234, {Max}); auto Result2 = Writer.addRecord(std::move(Record2)); - ASSERT_EQ(Result2, instrprof_error::counter_overflow); + ASSERT_EQ(InstrProfError::take(std::move(Result2)), + instrprof_error::counter_overflow); InstrProfRecord Record3(bar, 0x9012, {8}); auto Result3 = Writer.addRecord(std::move(Record3)); - ASSERT_EQ(Result3, instrprof_error::success); + ASSERT_EQ(InstrProfError::take(std::move(Result3)), + instrprof_error::success); InstrProfRecord Record4("baz", 0x5678, {3, 4}); Record4.reserveSites(IPVK_IndirectCallTarget, 1); InstrProfValueData VD4[] = {{uint64_t(bar), 1}}; Record4.addValueData(IPVK_IndirectCallTarget, 0, VD4, 1, nullptr); auto Result4 = Writer.addRecord(std::move(Record4)); - ASSERT_EQ(Result4, instrprof_error::success); + ASSERT_EQ(InstrProfError::take(std::move(Result4)), + instrprof_error::success); // Verify value data counter overflow. InstrProfRecord Record5("baz", 0x5678, {5, 6}); @@ -590,19 +598,21 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1_saturation) { InstrProfValueData VD5[] = {{uint64_t(bar), Max}}; Record5.addValueData(IPVK_IndirectCallTarget, 0, VD5, 1, nullptr); auto Result5 = Writer.addRecord(std::move(Record5)); - ASSERT_EQ(Result5, instrprof_error::counter_overflow); + ASSERT_EQ(InstrProfError::take(std::move(Result5)), + instrprof_error::counter_overflow); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); // Verify saturation of counts. - ErrorOr ReadRecord1 = + Expected ReadRecord1 = Reader->getInstrProfRecord("foo", 0x1234); - ASSERT_TRUE(NoError(ReadRecord1.getError())); + ASSERT_TRUE(NoError(ReadRecord1.takeError())); ASSERT_EQ(Max, ReadRecord1->Counts[0]); - ErrorOr ReadRecord2 = + Expected ReadRecord2 = Reader->getInstrProfRecord("baz", 0x5678); + ASSERT_TRUE(bool(ReadRecord2)); ASSERT_EQ(1U, ReadRecord2->getNumValueSites(IPVK_IndirectCallTarget)); std::unique_ptr VD = ReadRecord2->getValueForSite(IPVK_IndirectCallTarget, 0); @@ -647,8 +657,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge_site_trunc) { auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); - ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.getError())); + Expected R = Reader->getInstrProfRecord("caller", 0x1234); + ASSERT_TRUE(NoError(R.takeError())); std::unique_ptr VD( R->getValueForSite(IPVK_IndirectCallTarget, 0)); ASSERT_EQ(2U, R->getNumValueSites(IPVK_IndirectCallTarget));