Index: include/llvm/ProfileData/CoverageMappingReader.h =================================================================== --- include/llvm/ProfileData/CoverageMappingReader.h +++ include/llvm/ProfileData/CoverageMappingReader.h @@ -20,7 +20,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/Object/ObjectFile.h" #include "llvm/ProfileData/CoverageMapping.h" -#include "llvm/ProfileData/InstrProf.h" +#include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include @@ -159,6 +159,7 @@ std::vector Filenames; std::vector MappingRecords; size_t CurrentRecord; + std::unique_ptr Symtab; std::vector FunctionsFilenames; std::vector Expressions; std::vector MappingRegions; Index: include/llvm/ProfileData/InstrProf.h =================================================================== --- include/llvm/ProfileData/InstrProf.h +++ include/llvm/ProfileData/InstrProf.h @@ -16,8 +16,10 @@ #ifndef LLVM_PROFILEDATA_INSTRPROF_H_ #define LLVM_PROFILEDATA_INSTRPROF_H_ -#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MD5.h" #include #include #include @@ -47,6 +49,38 @@ return std::error_code(static_cast(E), instrprof_category()); } +namespace IndexedInstrProf { + +enum class HashT : uint32_t { + MD5, + + Last = MD5 +}; + +static inline uint64_t MD5Hash(StringRef Str) { + MD5 Hash; + Hash.update(Str); + llvm::MD5::MD5Result Result; + Hash.final(Result); + // Return the least significant 8 bytes. Our MD5 implementation returns the + // result in little endian, so we may need to swap bytes. + using namespace llvm::support; + return endian::read(Result); +} + +static inline uint64_t ComputeHash(HashT Type, StringRef K) { + switch (Type) { + case HashT::MD5: + return IndexedInstrProf::MD5Hash(K); + } + llvm_unreachable("Unhandled hash type"); +} + +const uint64_t Magic = 0x8169666f72706cff; // "\xfflprofi\x81" +const uint64_t Version = 4; +const HashT HashType = HashT::MD5; +} + enum InstrProfValueKind : uint32_t { IPVK_IndirectCallTarget = 0, @@ -54,22 +88,6 @@ IPVK_Last = IPVK_IndirectCallTarget }; -struct InstrProfStringTable { - // Set of string values in profiling data. - StringSet<> StringValueSet; - InstrProfStringTable() { StringValueSet.clear(); } - // Get a pointer to internal storage of a string in set - const char *getStringData(StringRef Str) { - auto Result = StringValueSet.find(Str); - return (Result == StringValueSet.end()) ? nullptr : Result->first().data(); - } - // Insert a string to StringTable - const char *insertString(StringRef Str) { - auto Result = StringValueSet.insert(Str); - return Result.first->first().data(); - } -}; - struct InstrProfValueSiteRecord { /// Typedef for a single TargetValue-NumTaken pair. typedef std::pair ValueDataPair; @@ -108,9 +126,15 @@ /// Profiling information for a single function. struct InstrProfRecord { InstrProfRecord() {} + InstrProfRecord(uint64_t NameKey, uint64_t Hash, std::vector Counts) + : NameKey(NameKey), Hash(Hash), Counts(std::move(Counts)) {} InstrProfRecord(StringRef Name, uint64_t Hash, std::vector Counts) - : Name(Name), Hash(Hash), Counts(std::move(Counts)) {} + : Name(Name), NameKey(0), Hash(Hash), Counts(std::move(Counts)) { + + NameKey = IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType, Name); + } StringRef Name; + uint64_t NameKey; uint64_t Hash; std::vector Counts; std::vector IndirectCallSites; Index: include/llvm/ProfileData/InstrProfReader.h =================================================================== --- include/llvm/ProfileData/InstrProfReader.h +++ include/llvm/ProfileData/InstrProfReader.h @@ -16,7 +16,9 @@ #define LLVM_PROFILEDATA_INSTRPROFREADER_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/ErrorOr.h" @@ -65,8 +67,6 @@ InstrProfIterator end() { return InstrProfIterator(); } protected: - /// String table for holding a unique copy of all the strings in the profile. - InstrProfStringTable StringTable; /// Set the current std::error_code and return same. std::error_code error(std::error_code EC) { @@ -132,34 +132,71 @@ private: /// The profile data file contents. std::unique_ptr DataBuffer; - struct ProfileData { + struct ProfileDataV1 { const uint32_t NameSize; const uint32_t NumCounters; const uint64_t FuncHash; - const IntPtrT NamePtr; + const IntPtrT Name; const IntPtrT CounterPtr; }; + struct ProfileData { + const uint64_t NameKey; + const uint64_t FuncHash; + const IntPtrT CounterPtr; + const uint32_t NumCounters; + }; struct RawHeader { const uint64_t Magic; const uint64_t Version; const uint64_t DataSize; const uint64_t CountersSize; - const uint64_t NamesSize; + const uint64_t NamesSize; // Used for V1 const uint64_t CountersDelta; - const uint64_t NamesDelta; + const uint64_t NamesDelta; // Used for V1 }; bool ShouldSwapBytes; uint64_t CountersDelta; uint64_t NamesDelta; - const ProfileData *Data; - const ProfileData *DataEnd; + union { + const ProfileData *Data; + const ProfileDataV1 *DataV1; + } U1; + union { + const ProfileData *DataEnd; + const ProfileDataV1 *DataEndV1; + } U2; const uint64_t *CountersStart; const char *NamesStart; const char *ProfileEnd; + uint64_t Version; RawInstrProfReader(const RawInstrProfReader &) = delete; RawInstrProfReader &operator=(const RawInstrProfReader &) = delete; + + ptrdiff_t getCounterOffset(ptrdiff_t DataOffset, uint64_t DataSize) { + if (Version == 1) + return DataOffset + sizeof(ProfileDataV1) * DataSize; + else + return DataOffset + sizeof(ProfileData) * DataSize; + } + void setDataEnd(uint64_t DataSize) { + if (Version == 1) + U2.DataEndV1 = U1.DataV1 + DataSize; + else + U2.DataEnd = U1.Data + DataSize; + } + void advanceData(void) { + if (Version == 1) + U1.Data++; + else + U1.DataV1++; + } + + std::error_code readNameFromData(uint64_t &NameKey, StringRef &RawName); + std::error_code readRawCountsFromData(InstrProfRecord &Record); + std::error_code readFuncHashFromData(uint64_t &FuncHash); + public: RawInstrProfReader(std::unique_ptr DataBuffer) : DataBuffer(std::move(DataBuffer)) { } @@ -188,17 +225,22 @@ typedef RawInstrProfReader RawInstrProfReader32; typedef RawInstrProfReader RawInstrProfReader64; -namespace IndexedInstrProf { -enum class HashT : uint32_t; -} - /// Trait for lookups into the on-disk hash table for the binary instrprof /// format. -class InstrProfLookupTrait { +template +inline KeyType ReadKeyHelper(const unsigned char *D, uint64_t N) { + return KeyType((const char *)D, N); +} + +template <> +inline uint64_t ReadKeyHelper(const unsigned char *D, uint64_t N) { + return *((const uint64_t *)D); +} + +template class InstrProfLookupTrait { std::vector DataBuffer; IndexedInstrProf::HashT HashType; unsigned FormatVersion; - std::vector> HashKeys; public: InstrProfLookupTrait(IndexedInstrProf::HashT HashType, unsigned FormatVersion) @@ -206,20 +248,17 @@ typedef ArrayRef data_type; - typedef StringRef internal_key_type; - typedef StringRef external_key_type; + typedef KeyType internal_key_type; + typedef KeyType external_key_type; typedef uint64_t hash_value_type; typedef uint64_t offset_type; - static bool EqualKey(StringRef A, StringRef B) { return A == B; } - static StringRef GetInternalKey(StringRef K) { return K; } - static StringRef GetExternalKey(StringRef K) { return K; } + static bool EqualKey(KeyType A, KeyType B) { return A == B; } + static KeyType GetInternalKey(KeyType K) { return K; } + static KeyType GetExternalKey(KeyType K) { return K; } - hash_value_type ComputeHash(StringRef K); + hash_value_type ComputeHash(KeyType K); - void setHashKeys(std::vector> HashKeys) { - this->HashKeys = std::move(HashKeys); - } static std::pair ReadKeyDataLength(const unsigned char *&D) { using namespace support; @@ -228,37 +267,85 @@ return std::make_pair(KeyLen, DataLen); } - StringRef ReadKey(const unsigned char *D, offset_type N) { - return StringRef((const char *)D, N); + KeyType ReadKey(const unsigned char *D, offset_type N) { + return ReadKeyHelper(D, N); } bool ReadValueProfilingData(const unsigned char *&D, const unsigned char *const End); - data_type ReadData(StringRef K, const unsigned char *D, offset_type N); + data_type ReadData(KeyType K, const unsigned char *D, offset_type N); }; -typedef OnDiskIterableChainedHashTable +typedef OnDiskIterableChainedHashTable> InstrProfReaderIndex; +typedef OnDiskIterableChainedHashTable> + InstrProfReaderIndexV3; -/// Reader for the indexed binary instrprof format. -class IndexedInstrProfReader : public InstrProfReader { +class InstrProfIndex { private: - /// The profile data file contents. - std::unique_ptr DataBuffer; /// The index into the profile data. std::unique_ptr Index; /// Iterator over the profile data. InstrProfReaderIndex::data_iterator RecordIterator; + /// The index into the profile data of v2 format. + std::unique_ptr IndexV3; + /// Iterator over the profile data. + InstrProfReaderIndexV3::data_iterator RecordIteratorV3; /// The file format version of the profile data. uint64_t FormatVersion; + +public: + InstrProfIndex() : Index(nullptr), IndexV3(nullptr) {} + void Init(const unsigned char *Buckets, const unsigned char *const Payload, + const unsigned char *const Base, IndexedInstrProf::HashT HashType, + uint64_t Version) { + FormatVersion = Version; + if (FormatVersion <= 3) { + IndexV3.reset(InstrProfReaderIndexV3::Create( + Buckets, Payload, Base, + InstrProfLookupTrait(HashType, Version))); + // Set up our iterator for readNextRecord. + RecordIteratorV3 = IndexV3->data_begin(); + } else { + Index.reset(InstrProfReaderIndex::Create( + Buckets, Payload, Base, + InstrProfLookupTrait(HashType, Version))); + RecordIterator = Index->data_begin(); + } + } + + std::error_code getRecordsForNextKey(ArrayRef &Data); + std::error_code getRecord(StringRef FuncName, uint64_t FuncNameKey, + ArrayRef &Data); + void advanceToNextKey() { + if (FormatVersion <= 3) + RecordIteratorV3++; + else + RecordIterator++; + } + bool atEnd() { + return (FormatVersion <= 3 ? RecordIteratorV3 == IndexV3->data_end() + : RecordIterator == Index->data_end()); + } +}; + +/// Reader for the indexed binary instrprof format. +class IndexedInstrProfReader : public InstrProfReader { +private: + /// The profile data file contents. + std::unique_ptr DataBuffer; + InstrProfIndex Index; /// The maximal execution count among all functions. uint64_t MaxFunctionCount; + std::error_code getFunctionCounts(StringRef FuncName, uint64_t FuncNameKey, + uint64_t FuncHash, + std::vector &Counts); IndexedInstrProfReader(const IndexedInstrProfReader &) = delete; IndexedInstrProfReader &operator=(const IndexedInstrProfReader &) = delete; public: IndexedInstrProfReader(std::unique_ptr DataBuffer) - : DataBuffer(std::move(DataBuffer)), Index(nullptr) {} + : DataBuffer(std::move(DataBuffer)), Index() {} /// Return true if the given buffer is in an indexed instrprof format. static bool hasFormat(const MemoryBuffer &DataBuffer); @@ -271,6 +358,8 @@ /// Fill Counts with the profile data for the given function name. std::error_code getFunctionCounts(StringRef FuncName, uint64_t FuncHash, std::vector &Counts); + std::error_code getFunctionCounts(uint64_t FuncNamekey, uint64_t FuncHash, + std::vector &Counts); /// Return the maximum of all known function counts. uint64_t getMaximumFunctionCount() { return MaxFunctionCount; } @@ -282,6 +371,44 @@ create(std::unique_ptr Buffer); }; +/// \brief A helper structure to access the data from a section +/// in an object file. +struct SymbolNameSectionData { + StringRef Data; + uint64_t Address; + + std::error_code load(object::SectionRef &Section) { + if (auto Err = Section.getContents(Data)) + return Err; + Address = Section.getAddress(); + return std::error_code(); + } + + std::error_code get(uint64_t Pointer, size_t Size, StringRef &Result); +}; + +/// Class to represent profile symbol table used by llvm-cov and llvm-profdata +/// tool +class ProfSymtab { + /// Map from md5hash key to function name strings. + DenseMap Symtab; + /// Data section that contains funciton names + SymbolNameSectionData SymtabSection; + bool UsesNameSection; + +public: + std::error_code getFunctionName(uintptr_t NameHashKeyOrAddr, size_t Size, + StringRef &Result); + ProfSymtab(object::ObjectFile::symbol_iterator_range Syms); + ProfSymtab(StringRef Data, uint64_t Base) : UsesNameSection(true) { + SymtabSection.Data = Data; + SymtabSection.Address = Base; + } + ProfSymtab(object::SectionRef &Section) : UsesNameSection(true) { + SymtabSection.load(Section); + } +}; + } // end namespace llvm #endif Index: include/llvm/ProfileData/InstrProfWriter.h =================================================================== --- include/llvm/ProfileData/InstrProfWriter.h +++ include/llvm/ProfileData/InstrProfWriter.h @@ -29,8 +29,7 @@ typedef SmallDenseMap ProfilingData; private: - InstrProfStringTable StringTable; - StringMap FunctionData; + DenseMap FunctionData; uint64_t MaxFunctionCount; public: InstrProfWriter() : MaxFunctionCount(0) {} Index: lib/CodeGen/CodeGenPGO.cpp =================================================================== --- lib/CodeGen/CodeGenPGO.cpp +++ lib/CodeGen/CodeGenPGO.cpp @@ -69,11 +69,9 @@ Linkage == llvm::GlobalValue::ExternalLinkage) Linkage = llvm::GlobalValue::PrivateLinkage; - auto *Value = - llvm::ConstantDataArray::getString(CGM.getLLVMContext(), FuncName, false); - FuncNameVar = - new llvm::GlobalVariable(CGM.getModule(), Value->getType(), true, Linkage, - Value, "__llvm_profile_name_" + FuncName); + FuncNameVar = new llvm::GlobalVariable( + CGM.getModule(), llvm::Type::getInt8Ty(CGM.getLLVMContext()), true, + Linkage, 0, "__llvm_prf_nm_" + FuncName); // Hide the symbol so that we correctly get a copy for each executable. if (!llvm::GlobalValue::isLocalLinkage(FuncNameVar->getLinkage())) Index: lib/CodeGen/CoverageMappingGen.h =================================================================== --- lib/CodeGen/CoverageMappingGen.h +++ lib/CodeGen/CoverageMappingGen.h @@ -54,6 +54,7 @@ CoverageSourceInfo &SourceInfo; llvm::SmallDenseMap FileEntries; std::vector FunctionRecords; + std::vector FunctionNames; llvm::StructType *FunctionRecordTy; std::string CoverageMappings; Index: lib/CodeGen/CoverageMappingGen.cpp =================================================================== --- lib/CodeGen/CoverageMappingGen.cpp +++ lib/CodeGen/CoverageMappingGen.cpp @@ -915,21 +915,26 @@ llvm::LLVMContext &Ctx = CGM.getLLVMContext(); auto *Int32Ty = llvm::Type::getInt32Ty(Ctx); auto *Int64Ty = llvm::Type::getInt64Ty(Ctx); - auto *Int8PtrTy = llvm::Type::getInt8PtrTy(Ctx); if (!FunctionRecordTy) { - llvm::Type *FunctionRecordTypes[] = {Int8PtrTy, Int32Ty, Int32Ty, Int64Ty}; + llvm::Type *FunctionRecordTypes[] = {Int64Ty, Int32Ty, Int32Ty, Int64Ty}; FunctionRecordTy = llvm::StructType::get(Ctx, makeArrayRef(FunctionRecordTypes), /*isPacked=*/true); } + auto FuncNameKey = llvm::IndexedInstrProf::ComputeHash( + llvm::IndexedInstrProf::HashType, + FunctionName->getName().substr(strlen("__llvm_prf_nm_"))); + llvm::Constant *FunctionRecordVals[] = { - llvm::ConstantExpr::getBitCast(FunctionName, Int8PtrTy), - llvm::ConstantInt::get(Int32Ty, FunctionNameValue.size()), + llvm::ConstantInt::get(Int64Ty, FuncNameKey), + llvm::ConstantInt::get(Int32Ty, 0), // NameSize field in legacy format llvm::ConstantInt::get(Int32Ty, CoverageMapping.size()), llvm::ConstantInt::get(Int64Ty, FunctionHash)}; FunctionRecords.push_back(llvm::ConstantStruct::get( FunctionRecordTy, makeArrayRef(FunctionRecordVals))); + FunctionNames.push_back(llvm::ConstantExpr::getBitCast( + FunctionName, llvm::Type::getInt8PtrTy(Ctx))); CoverageMappings += CoverageMapping; if (CGM.getCodeGenOpts().DumpCoverageMapping) { @@ -1018,6 +1023,16 @@ // Make sure the data doesn't get deleted. CGM.addUsedGlobal(CovData); + + // Create the deferred function records array + auto NamesArrTy = + llvm::ArrayType::get(llvm::Type::getInt8PtrTy(Ctx), FunctionNames.size()); + auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames); + // This variable will not be emitted to the object file. It is used + // to pass the list of names referenced to codegen. + new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true, + llvm::GlobalValue::InternalLinkage, NamesArrVal, + "__llvm_coverage_names"); } unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) { Index: lib/ProfileData/CoverageMappingReader.cpp =================================================================== --- lib/ProfileData/CoverageMappingReader.cpp +++ lib/ProfileData/CoverageMappingReader.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ProfileData/CoverageMappingReader.h" +#include "llvm/ProfileData/InstrProfReader.h" #include "llvm/ADT/DenseSet.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" @@ -290,36 +291,55 @@ return std::error_code(); } -namespace { +std::error_code SymbolNameSectionData::get(uint64_t Pointer, size_t Size, + StringRef &Result) { + if (Pointer < Address) + return coveragemap_error::malformed; + auto Offset = Pointer - Address; + if (Offset + Size > Data.size()) + return coveragemap_error::malformed; + Result = Data.substr(Pointer - Address, Size); + return std::error_code(); +} -/// \brief A helper structure to access the data from a section -/// in an object file. -struct SectionData { - StringRef Data; - uint64_t Address; +std::error_code ProfSymtab::getFunctionName(uintptr_t NameKeyOrAddr, + size_t Size, StringRef &Result) { + if (UsesNameSection) + return SymtabSection.get(NameKeyOrAddr, Size, Result); - std::error_code load(SectionRef &Section) { - if (auto Err = Section.getContents(Data)) - return Err; - Address = Section.getAddress(); - return std::error_code(); - } + auto Iterator = Symtab.find(NameKeyOrAddr); + if (Iterator == Symtab.end()) + return coveragemap_error::malformed; - std::error_code get(uint64_t Pointer, size_t Size, StringRef &Result) { - if (Pointer < Address) - return coveragemap_error::malformed; - auto Offset = Pointer - Address; - if (Offset + Size > Data.size()) - return coveragemap_error::malformed; - Result = Data.substr(Pointer - Address, Size); - return std::error_code(); + Result = Iterator->second; + return std::error_code(); +} + +ProfSymtab::ProfSymtab(object::ObjectFile::symbol_iterator_range Syms) { + UsesNameSection = false; + auto S = Syms.begin(); + auto E = Syms.end(); + for (; S != E; ++S) { + ErrorOr NameOrError = S->getName(); + if (!NameOrError) + continue; + StringRef Name = *NameOrError; + + // TODO: define name prefix + if (!Name.startswith("__llvm_prf_nm_")) + continue; + + StringRef RealName = Name.substr(strlen("__llvm_prf_nm_")); + uint64_t FuncNameKey = + IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType, RealName); + + Symtab[FuncNameKey] = RealName.str(); } -}; } template std::error_code readCoverageMappingData( - SectionData &ProfileNames, StringRef Data, + std::unique_ptr &ProfileNames, StringRef Data, std::vector &Records, std::vector &Filenames) { using namespace support; @@ -343,7 +363,9 @@ // Skip past the function records, saving the start and end for later. const char *FunBuf = Buf; - Buf += NRecords * (sizeof(T) + 2 * sizeof(uint32_t) + sizeof(uint64_t)); + // TODO : this is very error-prone. Need to define size and structure of + // Function Record in coverage mapping in a single place. + Buf += NRecords * (3 * sizeof(uint64_t)); const char *FunEnd = Buf; // Get the filenames. @@ -368,7 +390,8 @@ while (FunBuf < FunEnd) { // Read the function information - T NamePtr = endian::readNext(FunBuf); + uint64_t FuncNameKey = + endian::readNext(FunBuf); uint32_t NameSize = endian::readNext(FunBuf); uint32_t DataSize = endian::readNext(FunBuf); uint64_t FuncHash = endian::readNext(FunBuf); @@ -382,12 +405,13 @@ // Ignore this record if we already have a record that points to the same // function name. This is useful to ignore the redundant records for the // functions with ODR linkage. - if (!UniqueFunctionMappingData.insert(NamePtr).second) + if (!UniqueFunctionMappingData.insert(FuncNameKey).second) continue; // Finally, grab the name and create a record. StringRef FuncName; - if (std::error_code EC = ProfileNames.get(NamePtr, NameSize, FuncName)) + if (std::error_code EC = + ProfileNames->getFunctionName(FuncNameKey, NameSize, FuncName)) return EC; Records.push_back(BinaryCoverageReader::ProfileMappingRecord( CoverageMappingVersion(Version), FuncName, FuncHash, Mapping, @@ -400,11 +424,10 @@ static const char *TestingFormatMagic = "llvmcovmtestdata"; -static std::error_code loadTestingFormat(StringRef Data, - SectionData &ProfileNames, - StringRef &CoverageMapping, - uint8_t &BytesInAddress, - support::endianness &Endian) { +static std::error_code +loadTestingFormat(StringRef Data, std::unique_ptr &ProfileNames, + StringRef &CoverageMapping, uint8_t &BytesInAddress, + support::endianness &Endian) { BytesInAddress = 8; Endian = support::endianness::little; @@ -420,14 +443,14 @@ if (Data.size() < 1) return coveragemap_error::truncated; N = 0; - ProfileNames.Address = + uint64_t Address = decodeULEB128(reinterpret_cast(Data.data()), &N); if (N > Data.size()) return coveragemap_error::malformed; Data = Data.substr(N); if (Data.size() < ProfileNamesSize) return coveragemap_error::malformed; - ProfileNames.Data = Data.substr(0, ProfileNamesSize); + ProfileNames.reset(new ProfSymtab(Data.substr(0, ProfileNamesSize), Address)); CoverageMapping = Data.substr(ProfileNamesSize); return std::error_code(); } @@ -443,12 +466,11 @@ return coveragemap_error::no_data_found; } -static std::error_code loadBinaryFormat(MemoryBufferRef ObjectBuffer, - SectionData &ProfileNames, - StringRef &CoverageMapping, - uint8_t &BytesInAddress, - support::endianness &Endian, - StringRef Arch) { +static std::error_code +loadBinaryFormat(MemoryBufferRef ObjectBuffer, + std::unique_ptr &ProfileNames, + StringRef &CoverageMapping, uint8_t &BytesInAddress, + support::endianness &Endian, StringRef Arch) { auto BinOrErr = object::createBinary(ObjectBuffer); if (std::error_code EC = BinOrErr.getError()) return EC; @@ -476,10 +498,6 @@ Endian = OF->isLittleEndian() ? support::endianness::little : support::endianness::big; - // Look for the sections that we are interested in. - auto NamesSection = lookupSection(*OF, "__llvm_prf_names"); - if (auto EC = NamesSection.getError()) - return EC; auto CoverageSection = lookupSection(*OF, "__llvm_covmap"); if (auto EC = CoverageSection.getError()) return EC; @@ -487,8 +505,8 @@ // Get the contents of the given sections. if (std::error_code EC = CoverageSection->getContents(CoverageMapping)) return EC; - if (std::error_code EC = ProfileNames.load(*NamesSection)) - return EC; + + ProfileNames.reset(new ProfSymtab(OF->symbols())); return std::error_code(); } @@ -498,7 +516,7 @@ StringRef Arch) { std::unique_ptr Reader(new BinaryCoverageReader()); - SectionData Profile; + std::unique_ptr &Profile = Reader->Symtab; StringRef Coverage; uint8_t BytesInAddress; support::endianness Endian; Index: lib/ProfileData/InstrProfIndexed.h =================================================================== --- lib/ProfileData/InstrProfIndexed.h +++ /dev/null @@ -1,56 +0,0 @@ -//=-- InstrProfIndexed.h - Indexed profiling format support -------*- C++ -*-=// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Shared header for the instrumented profile data reader and writer. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_PROFILEDATA_INSTRPROFINDEXED_H -#define LLVM_LIB_PROFILEDATA_INSTRPROFINDEXED_H - -#include "llvm/Support/Endian.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MD5.h" - -namespace llvm { - -namespace IndexedInstrProf { -enum class HashT : uint32_t { - MD5, - - Last = MD5 -}; - -static inline uint64_t MD5Hash(StringRef Str) { - MD5 Hash; - Hash.update(Str); - llvm::MD5::MD5Result Result; - Hash.final(Result); - // Return the least significant 8 bytes. Our MD5 implementation returns the - // result in little endian, so we may need to swap bytes. - using namespace llvm::support; - return endian::read(Result); -} - -static inline uint64_t ComputeHash(HashT Type, StringRef K) { - switch (Type) { - case HashT::MD5: - return IndexedInstrProf::MD5Hash(K); - } - llvm_unreachable("Unhandled hash type"); -} - -const uint64_t Magic = 0x8169666f72706cff; // "\xfflprofi\x81" -const uint64_t Version = 3; -const HashT HashType = HashT::MD5; -} - -} // end namespace llvm - -#endif Index: lib/ProfileData/InstrProfReader.cpp =================================================================== --- lib/ProfileData/InstrProfReader.cpp +++ lib/ProfileData/InstrProfReader.cpp @@ -13,7 +13,6 @@ //===----------------------------------------------------------------------===// #include "llvm/ProfileData/InstrProfReader.h" -#include "InstrProfIndexed.h" #include "llvm/ADT/STLExtras.h" #include @@ -108,6 +107,8 @@ // Read the function name. Record.Name = *Line++; + Record.NameKey = + IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType, Record.Name); // Read the function hash. if (Line.is_at_end()) @@ -217,16 +218,15 @@ return readHeader(*Header); } -static uint64_t getRawVersion() { - return 1; -} +static uint64_t getRawVersion() { return 2; } template std::error_code RawInstrProfReader::readHeader(const RawHeader &Header) { - if (swap(Header.Version) != getRawVersion()) + if (swap(Header.Version) > getRawVersion()) return error(instrprof_error::unsupported_version); + Version = swap(Header.Version); CountersDelta = swap(Header.CountersDelta); NamesDelta = swap(Header.NamesDelta); auto DataSize = swap(Header.DataSize); @@ -234,7 +234,7 @@ auto NamesSize = swap(Header.NamesSize); ptrdiff_t DataOffset = sizeof(RawHeader); - ptrdiff_t CountersOffset = DataOffset + sizeof(ProfileData) * DataSize; + ptrdiff_t CountersOffset = getCounterOffset(DataOffset, DataSize); ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize; size_t ProfileSize = NamesOffset + sizeof(char) * NamesSize; @@ -242,8 +242,8 @@ if (Start + ProfileSize > DataBuffer->getBufferEnd()) return error(instrprof_error::bad_header); - Data = reinterpret_cast(Start + DataOffset); - DataEnd = Data + DataSize; + U1.Data = reinterpret_cast(Start + DataOffset); + setDataEnd(DataSize); CountersStart = reinterpret_cast(Start + CountersOffset); NamesStart = Start + NamesOffset; ProfileEnd = Start + ProfileSize; @@ -253,29 +253,48 @@ template std::error_code -RawInstrProfReader::readNextRecord(InstrProfRecord &Record) { - if (Data == DataEnd) - if (std::error_code EC = readNextHeader(ProfileEnd)) - return EC; +RawInstrProfReader::readNameFromData(uint64_t &NameKey, + StringRef &RawName) { + if (Version == 1) { + RawName = StringRef(getName(U1.DataV1->Name), swap(U1.DataV1->NameSize)); + if (RawName.data() < NamesStart || + RawName.data() + RawName.size() > DataBuffer->getBufferEnd()) + return error(instrprof_error::malformed); + NameKey = + IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType, RawName); + } else { + RawName = StringRef(); + NameKey = U1.Data->NameKey; + } + return success(); +} + +template +std::error_code +RawInstrProfReader::readRawCountsFromData(InstrProfRecord &Record) { + + uint32_t NumCounters; + IntPtrT CounterPtr; + if (Version == 1) { + NumCounters = swap(U1.DataV1->NumCounters); + CounterPtr = U1.DataV1->CounterPtr; + } else { + NumCounters = swap(U1.Data->NumCounters); + CounterPtr = U1.Data->CounterPtr; + } - // Get the raw data. - StringRef RawName(getName(Data->NamePtr), swap(Data->NameSize)); - uint32_t NumCounters = swap(Data->NumCounters); if (NumCounters == 0) return error(instrprof_error::malformed); - auto RawCounts = makeArrayRef(getCounter(Data->CounterPtr), NumCounters); - // Check bounds. + auto RawCounts = makeArrayRef(getCounter(CounterPtr), NumCounters); + auto *NamesStartAsCounter = reinterpret_cast(NamesStart); - if (RawName.data() < NamesStart || - RawName.data() + RawName.size() > DataBuffer->getBufferEnd() || - RawCounts.data() < CountersStart || + + // Check bounds. + if (RawCounts.data() < CountersStart || RawCounts.data() + RawCounts.size() > NamesStartAsCounter) return error(instrprof_error::malformed); - // Store the data in Record, byte-swapping as necessary. - Record.Hash = swap(Data->FuncHash); - Record.Name = RawName; if (ShouldSwapBytes) { Record.Counts.clear(); Record.Counts.reserve(RawCounts.size()); @@ -284,8 +303,38 @@ } else Record.Counts = RawCounts; + return success(); +} + +template +std::error_code +RawInstrProfReader::readFuncHashFromData(uint64_t &FuncHash) { + // Store the data in Record, byte-swapping as necessary. + if (Version == 1) + FuncHash = swap(U1.DataV1->FuncHash); + else + FuncHash = swap(U1.Data->FuncHash); + return success(); +} + +template +std::error_code +RawInstrProfReader::readNextRecord(InstrProfRecord &Record) { + if (U1.Data == U2.DataEnd) + if (std::error_code EC = readNextHeader(ProfileEnd)) + return EC; + + if (std::error_code EC = readNameFromData(Record.NameKey, Record.Name)) + return EC; + + if (std::error_code EC = readFuncHashFromData(Record.Hash)) + return EC; + + if (std::error_code EC = readRawCountsFromData(Record)) + return EC; + // Iterate. - ++Data; + advanceData(); return success(); } @@ -294,15 +343,22 @@ template class RawInstrProfReader; } -InstrProfLookupTrait::hash_value_type -InstrProfLookupTrait::ComputeHash(StringRef K) { +namespace llvm { +template +typename InstrProfLookupTrait::hash_value_type +InstrProfLookupTrait::ComputeHash(KeyType K) { return IndexedInstrProf::ComputeHash(HashType, K); } -typedef InstrProfLookupTrait::data_type data_type; -typedef InstrProfLookupTrait::offset_type offset_type; +template <> +InstrProfLookupTrait::hash_value_type +InstrProfLookupTrait::ComputeHash(uint64_t K) { + return K; +} +} -bool InstrProfLookupTrait::ReadValueProfilingData( +template +bool InstrProfLookupTrait::ReadValueProfilingData( const unsigned char *&D, const unsigned char *const End) { using namespace support; @@ -337,18 +393,6 @@ for (uint64_t VCount = 0; VCount < ValueDataCount; ++VCount) { uint64_t Value = endian::readNext(D); uint64_t NumTaken = endian::readNext(D); - switch (ValueKind) { - case IPVK_IndirectCallTarget: { - auto Result = - std::lower_bound(HashKeys.begin(), HashKeys.end(), Value, - [](const std::pair &LHS, - uint64_t RHS) { return LHS.first < RHS; }); - assert(Result != HashKeys.end() && - "Hash does not match any known keys\n"); - Value = (uint64_t)Result->second; - break; - } - } VSiteRecord.ValueData.push_back(std::make_pair(Value, NumTaken)); } ValueSites.push_back(std::move(VSiteRecord)); @@ -357,8 +401,10 @@ return true; } -data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D, - offset_type N) { +template +typename InstrProfLookupTrait::data_type +InstrProfLookupTrait::ReadData(KeyType K, const unsigned char *D, + offset_type N) { // Check if the data is corrupt. If so, don't try to read it. if (N % sizeof(uint64_t)) return data_type(); @@ -394,7 +440,7 @@ DataBuffer.push_back(InstrProfRecord(K, Hash, std::move(CounterBuffer))); // Read value profiling data - if (FormatVersion > 2 && !ReadValueProfilingData(D, End)) { + if (FormatVersion > 3 && !ReadValueProfilingData(D, End)) { DataBuffer.clear(); return data_type(); } @@ -426,7 +472,7 @@ return error(instrprof_error::bad_magic); // Read the version. - FormatVersion = endian::readNext(Cur); + uint64_t FormatVersion = endian::readNext(Cur); if (FormatVersion > IndexedInstrProf::Version) return error(instrprof_error::unsupported_version); @@ -441,36 +487,63 @@ uint64_t HashOffset = endian::readNext(Cur); // The rest of the file is an on disk hash table. - Index.reset(InstrProfReaderIndex::Create( - Start + HashOffset, Cur, Start, - InstrProfLookupTrait(HashType, FormatVersion))); - - // Form the map of hash values to const char* keys in profiling data. - std::vector> HashKeys; - for (auto Key : Index->keys()) { - const char *KeyTableRef = StringTable.insertString(Key); - HashKeys.push_back(std::make_pair(ComputeHash(HashType, Key), KeyTableRef)); - } - std::sort(HashKeys.begin(), HashKeys.end(), less_first()); - HashKeys.erase(std::unique(HashKeys.begin(), HashKeys.end()), HashKeys.end()); - // Set the hash key map for the InstrLookupTrait - Index->getInfoObj().setHashKeys(std::move(HashKeys)); - // Set up our iterator for readNextRecord. - RecordIterator = Index->data_begin(); + Index.Init(Start + HashOffset, Cur, Start, HashType, FormatVersion); return success(); } -std::error_code IndexedInstrProfReader::getFunctionCounts( - StringRef FuncName, uint64_t FuncHash, std::vector &Counts) { - auto Iter = Index->find(FuncName); - if (Iter == Index->end()) - return error(instrprof_error::unknown_function); +std::error_code InstrProfIndex::getRecord(StringRef FuncName, + uint64_t FuncNameKey, + ArrayRef &Data) { + + if (FormatVersion <= 3) { + assert(!FuncName.empty()); + auto Iter = IndexV3->find(FuncName); + if (Iter == IndexV3->end()) + return instrprof_error::unknown_function; + + // Found it. Look for counters with the right hash. + Data = (*Iter); + } else { + auto Iter = Index->find(FuncNameKey); + if (Iter == Index->end()) + return instrprof_error::unknown_function; + + // Found it. Look for counters with the right hash. + Data = (*Iter); + } - // Found it. Look for counters with the right hash. - ArrayRef Data = (*Iter); if (Data.empty()) - return error(instrprof_error::malformed); + return instrprof_error::malformed; + + return instrprof_error::success; +} + +std::error_code +InstrProfIndex::getRecordsForNextKey(ArrayRef &Data) { + // Are we out of records? + if (atEnd()) + return instrprof_error::eof; + + if (FormatVersion <= 3) + Data = *RecordIteratorV3; + else + Data = *RecordIterator; + + if (Data.empty()) + return instrprof_error::malformed; + + return instrprof_error::success; +} + +std::error_code IndexedInstrProfReader::getFunctionCounts( + StringRef FuncName, uint64_t FuncNameKey, uint64_t FuncHash, + std::vector &Counts) { + + ArrayRef Data; + std::error_code EC = Index.getRecord(FuncName, FuncNameKey, Data); + if (EC != instrprof_error::success) + return error(EC); for (unsigned I = 0, E = Data.size(); I < E; ++I) { // Check for a match and fill the vector if there is one. @@ -483,19 +556,31 @@ } std::error_code -IndexedInstrProfReader::readNextRecord(InstrProfRecord &Record) { - // Are we out of records? - if (RecordIterator == Index->data_end()) - return error(instrprof_error::eof); +IndexedInstrProfReader::getFunctionCounts(StringRef FuncName, uint64_t FuncHash, + std::vector &Counts) { + uint64_t FuncNameKey = + IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType, FuncName); + return getFunctionCounts(FuncName, FuncNameKey, FuncHash, Counts); +} - if ((*RecordIterator).empty()) - return error(instrprof_error::malformed); +std::error_code IndexedInstrProfReader::getFunctionCounts( + uint64_t FuncNameKey, uint64_t FuncHash, std::vector &Counts) { + return getFunctionCounts(StringRef(), FuncNameKey, FuncHash, Counts); +} + +std::error_code +IndexedInstrProfReader::readNextRecord(InstrProfRecord &Record) { static unsigned RecordIndex = 0; - ArrayRef Data = (*RecordIterator); + + ArrayRef Data; + std::error_code EC = Index.getRecordsForNextKey(Data); + if (EC != instrprof_error::success) + return error(EC); + Record = Data[RecordIndex++]; if (RecordIndex >= Data.size()) { - ++RecordIterator; + Index.advanceToNextKey(); RecordIndex = 0; } return success(); Index: lib/ProfileData/InstrProfWriter.cpp =================================================================== --- lib/ProfileData/InstrProfWriter.cpp +++ lib/ProfileData/InstrProfWriter.cpp @@ -13,7 +13,6 @@ //===----------------------------------------------------------------------===// #include "llvm/ProfileData/InstrProfWriter.h" -#include "InstrProfIndexed.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/OnDiskHashTable.h" @@ -23,8 +22,8 @@ namespace { class InstrProfRecordTrait { public: - typedef StringRef key_type; - typedef StringRef key_type_ref; + typedef uint64_t key_type; + typedef uint64_t key_type_ref; typedef const InstrProfWriter::ProfilingData *const data_type; typedef const InstrProfWriter::ProfilingData *const data_type_ref; @@ -32,16 +31,14 @@ typedef uint64_t hash_value_type; typedef uint64_t offset_type; - static hash_value_type ComputeHash(key_type_ref K) { - return IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType, K); - } + static hash_value_type ComputeHash(key_type_ref K) { return K; } static std::pair EmitKeyDataLength(raw_ostream &Out, key_type_ref K, data_type_ref V) { using namespace llvm::support; endian::Writer LE(Out); - offset_type N = K.size(); + offset_type N = sizeof(key_type_ref); LE.write(N); offset_type M = 0; @@ -71,7 +68,9 @@ } static void EmitKey(raw_ostream &Out, key_type_ref K, offset_type N){ - Out.write(K.data(), N); + using namespace llvm::support; + endian::Writer LE(Out); + LE.write(K); } static void EmitData(raw_ostream &Out, key_type_ref, data_type_ref V, @@ -104,10 +103,7 @@ // Write number of value data pairs at this value site LE.write(I.ValueData.size()); for (auto V : I.ValueData) { - if (Kind == IPVK_IndirectCallTarget) - LE.write(ComputeHash((const char *)V.first)); - else - LE.write(V.first); + LE.write(V.first); LE.write(V.second); } } @@ -159,17 +155,8 @@ return instrprof_error::success; } -void InstrProfWriter::updateStringTableReferences(InstrProfRecord &I) { - I.Name = StringTable.insertString(I.Name); - for (auto &VSite : I.IndirectCallSites) - for (auto &VData : VSite.ValueData) - VData.first = - (uint64_t)StringTable.insertString((const char *)VData.first); -} - std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I) { - updateStringTableReferences(I); - auto &ProfileDataMap = FunctionData[I.Name]; + auto &ProfileDataMap = FunctionData[I.NameKey]; auto Where = ProfileDataMap.find(I.Hash); if (Where == ProfileDataMap.end()) { @@ -191,7 +178,7 @@ // Populate the hash table generator. for (const auto &I : FunctionData) - Generator.insert(I.getKey(), &I.getValue()); + Generator.insert(I.getFirst(), &I.getSecond()); using namespace llvm::support; endian::Writer LE(OS); Index: lib/Transforms/Instrumentation/InstrProfiling.cpp =================================================================== --- lib/Transforms/Instrumentation/InstrProfiling.cpp +++ lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -14,8 +14,10 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/Instrumentation.h" +#include "llvm/ProfileData/InstrProf.h" #include "llvm/ADT/Triple.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" @@ -61,11 +63,6 @@ return isMachO() ? "__DATA,__llvm_prf_cnts" : "__llvm_prf_cnts"; } - /// Get the section name for the name variables. - StringRef getNameSection() const { - return isMachO() ? "__DATA,__llvm_prf_names" : "__llvm_prf_names"; - } - /// Get the section name for the profile data variables. StringRef getDataSection() const { return isMachO() ? "__DATA,__llvm_prf_data" : "__llvm_prf_data"; @@ -80,7 +77,8 @@ void lowerIncrement(InstrProfIncrementInst *Inc); /// Set up the section and uses for coverage data and its references. - void lowerCoverageData(GlobalVariable *CoverageData); + void lowerCoverageData(GlobalVariable *CoverageData, + GlobalVariable *CoverageNames); /// Get the region counters for an increment, creating them if necessary. /// @@ -128,7 +126,9 @@ MadeChange = true; } if (GlobalVariable *Coverage = M.getNamedGlobal("__llvm_coverage_mapping")) { - lowerCoverageData(Coverage); + GlobalVariable *CoverageNames = M.getNamedGlobal("__llvm_coverage_names"); + assert(CoverageNames); + lowerCoverageData(Coverage, CoverageNames); MadeChange = true; } if (!MadeChange) @@ -153,40 +153,46 @@ Inc->eraseFromParent(); } -void InstrProfiling::lowerCoverageData(GlobalVariable *CoverageData) { +void InstrProfiling::lowerCoverageData(GlobalVariable *CoverageData, + GlobalVariable *CoverageNames) { CoverageData->setSection(getCoverageSection()); CoverageData->setAlignment(8); - Constant *Init = CoverageData->getInitializer(); - // We're expecting { i32, i32, i32, i32, [n x { i8*, i32, i32 }], [m x i8] } + Constant *Init __attribute__((unused)) = CoverageData->getInitializer(); + // We're expecting { i32, i32, i32, i32, [n x { i64, i32, i32, i64 }], [m x + // i8] } // for some C. If not, the frontend's given us something broken. assert(Init->getNumOperands() == 6 && "bad number of fields in coverage map"); assert(isa(Init->getAggregateElement(4)) && "invalid function list in coverage map"); - ConstantArray *Records = cast(Init->getAggregateElement(4)); - for (unsigned I = 0, E = Records->getNumOperands(); I < E; ++I) { - Constant *Record = Records->getOperand(I); - Value *V = const_cast(Record->getOperand(0))->stripPointerCasts(); - assert(isa(V) && "Missing reference to function name"); - GlobalVariable *Name = cast(V); + ConstantArray *Names = cast(CoverageNames->getInitializer()); + + for (unsigned I = 0, E = Names->getNumOperands(); I < E; ++I) { + Constant *NC = Names->getOperand(I); + + assert(isa(NC) && "Missing reference to function name"); + GlobalVariable *Name = cast(NC); // If we have region counters for this name, we've already handled it. auto It = RegionCounters.find(Name); if (It != RegionCounters.end()) continue; - // Move the name variable to the right section. - Name->setSection(getNameSection()); - Name->setAlignment(1); + // FE never emits the function with the name, but it is referenced + // by coverage data. Force emitting the name. + // Reset Name variable's linkage + Name->setLinkage(GlobalValue::ExternalWeakLinkage); + // Mark the name variable as used so that it isn't stripped out. + UsedVars.push_back(Name); } } /// Get the name of a profiling variable for a particular function. static std::string getVarName(InstrProfIncrementInst *Inc, StringRef VarName) { - auto *Arr = cast(Inc->getName()->getInitializer()); - StringRef Name = Arr->isCString() ? Arr->getAsCString() : Arr->getAsString(); - return ("__llvm_profile_" + VarName + "_" + Name).str(); + // TODO define a macro for __llvm_prf_nm_ prefix and its size + StringRef Name = Inc->getName()->getName().substr(strlen("__llvm_prf_nm_")); + return ("__llvm_prf_" + VarName + "_" + Name).str(); } GlobalVariable * @@ -196,17 +202,10 @@ if (It != RegionCounters.end()) return It->second; - // Move the name variable to the right section. Place them in a COMDAT group - // if the associated function is a COMDAT. This will make sure that - // only one copy of counters of the COMDAT function will be emitted after - // linking. Function *Fn = Inc->getParent()->getParent(); Comdat *ProfileVarsComdat = nullptr; if (Fn->hasComdat()) ProfileVarsComdat = M->getOrInsertComdat(StringRef(getVarName(Inc, "vars"))); - Name->setSection(getNameSection()); - Name->setAlignment(1); - Name->setComdat(ProfileVarsComdat); uint64_t NumCounters = Inc->getNumCounters()->getZExtValue(); LLVMContext &Ctx = M->getContext(); @@ -215,7 +214,7 @@ // Create the counters variable. auto *Counters = new GlobalVariable(*M, CounterTy, false, Name->getLinkage(), Constant::getNullValue(CounterTy), - getVarName(Inc, "counters")); + getVarName(Inc, "cnts")); Counters->setVisibility(Name->getVisibility()); Counters->setSection(getCountersSection()); Counters->setAlignment(8); @@ -224,20 +223,20 @@ RegionCounters[Inc->getName()] = Counters; // Create data variable. - auto *NameArrayTy = Name->getType()->getPointerElementType(); auto *Int32Ty = Type::getInt32Ty(Ctx); auto *Int64Ty = Type::getInt64Ty(Ctx); - auto *Int8PtrTy = Type::getInt8PtrTy(Ctx); auto *Int64PtrTy = Type::getInt64PtrTy(Ctx); - Type *DataTypes[] = {Int32Ty, Int32Ty, Int64Ty, Int8PtrTy, Int64PtrTy}; + auto FuncNameKey = IndexedInstrProf::ComputeHash( + IndexedInstrProf::HashType, + Inc->getName()->getName().substr(strlen("__llvm_prf_nm_"))); + Type *DataTypes[] = {Int64Ty, Int64Ty, Int64PtrTy, Int32Ty}; auto *DataTy = StructType::get(Ctx, makeArrayRef(DataTypes)); Constant *DataVals[] = { - ConstantInt::get(Int32Ty, NameArrayTy->getArrayNumElements()), - ConstantInt::get(Int32Ty, NumCounters), + ConstantInt::get(Int64Ty, FuncNameKey), ConstantInt::get(Int64Ty, Inc->getHash()->getZExtValue()), - ConstantExpr::getBitCast(Name, Int8PtrTy), - ConstantExpr::getBitCast(Counters, Int64PtrTy)}; + ConstantExpr::getBitCast(Counters, Int64PtrTy), + ConstantInt::get(Int32Ty, NumCounters)}; auto *Data = new GlobalVariable(*M, DataTy, true, Name->getLinkage(), ConstantStruct::get(DataTy, DataVals), getVarName(Inc, "data")); @@ -249,6 +248,11 @@ // Mark the data variable as used so that it isn't stripped out. UsedVars.push_back(Data); + // Reset Name variable's linkage + Name->setLinkage(GlobalValue::ExternalWeakLinkage); + // Mark the name variable as used so that it isn't stripped out. + UsedVars.push_back(Name); + return Counters; } @@ -274,7 +278,8 @@ IRBuilder<> IRB(BasicBlock::Create(M->getContext(), "", RegisterF)); for (Value *Data : UsedVars) - IRB.CreateCall(RuntimeRegisterF, IRB.CreateBitCast(Data, VoidPtrTy)); + if (!cast(Data)->isDeclaration()) + IRB.CreateCall(RuntimeRegisterF, IRB.CreateBitCast(Data, VoidPtrTy)); IRB.CreateRetVoid(); } Index: lib/profile/InstrProfiling.h =================================================================== --- lib/profile/InstrProfiling.h +++ lib/profile/InstrProfiling.h @@ -30,11 +30,10 @@ #define PROFILE_HEADER_SIZE 7 typedef struct __llvm_profile_data { - const uint32_t NameSize; - const uint32_t NumCounters; + const uint64_t FuncKey; const uint64_t FuncHash; - const char *const Name; uint64_t *const Counters; + const uint32_t NumCounters; } __llvm_profile_data; /*! @@ -52,8 +51,6 @@ const __llvm_profile_data *__llvm_profile_begin_data(void); const __llvm_profile_data *__llvm_profile_end_data(void); -const char *__llvm_profile_begin_names(void); -const char *__llvm_profile_end_names(void); uint64_t *__llvm_profile_begin_counters(void); uint64_t *__llvm_profile_end_counters(void); Index: lib/profile/InstrProfiling.c =================================================================== --- lib/profile/InstrProfiling.c +++ lib/profile/InstrProfiling.c @@ -36,7 +36,7 @@ __attribute__((visibility("hidden"))) uint64_t __llvm_profile_get_version(void) { /* This should be bumped any time the output format changes. */ - return 1; + return 2; } __attribute__((visibility("hidden"))) Index: lib/profile/InstrProfilingBuffer.c =================================================================== --- lib/profile/InstrProfilingBuffer.c +++ lib/profile/InstrProfilingBuffer.c @@ -18,28 +18,22 @@ const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); const uint64_t *CountersBegin = __llvm_profile_begin_counters(); const uint64_t *CountersEnd = __llvm_profile_end_counters(); - const char *NamesBegin = __llvm_profile_begin_names(); - const char *NamesEnd = __llvm_profile_end_names(); return __llvm_profile_get_size_for_buffer_internal( - DataBegin, DataEnd, CountersBegin, CountersEnd, NamesBegin, NamesEnd); + DataBegin, DataEnd, CountersBegin, CountersEnd); } #define PROFILE_RANGE_SIZE(Range) (Range##End - Range##Begin) -__attribute__((visibility("hidden"))) -uint64_t __llvm_profile_get_size_for_buffer_internal( +__attribute__((visibility("hidden"))) uint64_t + __llvm_profile_get_size_for_buffer_internal( const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, - const uint64_t *CountersEnd, const char *NamesBegin, - const char *NamesEnd) { + const uint64_t *CountersEnd) { /* Match logic in __llvm_profile_write_buffer(). */ - const uint64_t NamesSize = PROFILE_RANGE_SIZE(Names) * sizeof(char); - const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t); return sizeof(uint64_t) * PROFILE_HEADER_SIZE + - PROFILE_RANGE_SIZE(Data) * sizeof(__llvm_profile_data) + - PROFILE_RANGE_SIZE(Counters) * sizeof(uint64_t) + - NamesSize + Padding; + PROFILE_RANGE_SIZE(Data) * sizeof(__llvm_profile_data) + + PROFILE_RANGE_SIZE(Counters) * sizeof(uint64_t); } __attribute__((visibility("hidden"))) @@ -51,19 +45,15 @@ const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); const uint64_t *CountersBegin = __llvm_profile_begin_counters(); const uint64_t *CountersEnd = __llvm_profile_end_counters(); - const char *NamesBegin = __llvm_profile_begin_names(); - const char *NamesEnd = __llvm_profile_end_names(); return __llvm_profile_write_buffer_internal(Buffer, DataBegin, DataEnd, - CountersBegin, CountersEnd, - NamesBegin, NamesEnd); + CountersBegin, CountersEnd); } -__attribute__((visibility("hidden"))) -int __llvm_profile_write_buffer_internal( +__attribute__((visibility("hidden"))) int __llvm_profile_write_buffer_internal( char *Buffer, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, - const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) { + const uint64_t *CountersEnd) { /* Match logic in __llvm_profile_get_size_for_buffer(). * Match logic in __llvm_profile_write_file(). */ @@ -71,11 +61,6 @@ /* Calculate size of sections. */ const uint64_t DataSize = DataEnd - DataBegin; const uint64_t CountersSize = CountersEnd - CountersBegin; - const uint64_t NamesSize = NamesEnd - NamesBegin; - const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t); - - /* Enough zeroes for padding. */ - const char Zeroes[sizeof(uint64_t)] = {0}; /* Create the header. */ uint64_t Header[PROFILE_HEADER_SIZE]; @@ -83,9 +68,9 @@ Header[1] = __llvm_profile_get_version(); Header[2] = DataSize; Header[3] = CountersSize; - Header[4] = NamesSize; + Header[4] = 0; /* For V1 */ Header[5] = (uintptr_t)CountersBegin; - Header[6] = (uintptr_t)NamesBegin; + Header[6] = 0; /* For V1 */ /* Write the data. */ #define UPDATE_memcpy(Data, Size) \ @@ -96,8 +81,6 @@ UPDATE_memcpy(Header, PROFILE_HEADER_SIZE * sizeof(uint64_t)); UPDATE_memcpy(DataBegin, DataSize * sizeof(__llvm_profile_data)); UPDATE_memcpy(CountersBegin, CountersSize * sizeof(uint64_t)); - UPDATE_memcpy(NamesBegin, NamesSize * sizeof(char)); - UPDATE_memcpy(Zeroes, Padding * sizeof(char)); #undef UPDATE_memcpy return 0; Index: lib/profile/InstrProfilingFile.c =================================================================== --- lib/profile/InstrProfilingFile.c +++ lib/profile/InstrProfilingFile.c @@ -22,17 +22,10 @@ const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); const uint64_t *CountersBegin = __llvm_profile_begin_counters(); const uint64_t *CountersEnd = __llvm_profile_end_counters(); - const char *NamesBegin = __llvm_profile_begin_names(); - const char *NamesEnd = __llvm_profile_end_names(); /* Calculate size of sections. */ const uint64_t DataSize = DataEnd - DataBegin; const uint64_t CountersSize = CountersEnd - CountersBegin; - const uint64_t NamesSize = NamesEnd - NamesBegin; - const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t); - - /* Enough zeroes for padding. */ - const char Zeroes[sizeof(uint64_t)] = {0}; /* Create the header. */ uint64_t Header[PROFILE_HEADER_SIZE]; @@ -40,9 +33,9 @@ Header[1] = __llvm_profile_get_version(); Header[2] = DataSize; Header[3] = CountersSize; - Header[4] = NamesSize; + Header[4] = 0; /* NameSize unused */ Header[5] = (uintptr_t)CountersBegin; - Header[6] = (uintptr_t)NamesBegin; + Header[6] = 0; /* NamesBegin unused */ /* Write the data. */ #define CHECK_fwrite(Data, Size, Length, File) \ @@ -50,8 +43,6 @@ CHECK_fwrite(Header, sizeof(uint64_t), PROFILE_HEADER_SIZE, File); CHECK_fwrite(DataBegin, sizeof(__llvm_profile_data), DataSize, File); CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File); - CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File); - CHECK_fwrite(Zeroes, sizeof(char), Padding, File); #undef CHECK_fwrite return 0; Index: lib/profile/InstrProfilingInternal.h =================================================================== --- lib/profile/InstrProfilingInternal.h +++ lib/profile/InstrProfilingInternal.h @@ -20,8 +20,7 @@ */ uint64_t __llvm_profile_get_size_for_buffer_internal( const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, - const uint64_t *CountersBegin, const uint64_t *CountersEnd, - const char *NamesBegin, const char *NamesEnd); + const uint64_t *CountersBegin, const uint64_t *CountersEnd); /*! * \brief Write instrumentation data to the given buffer, given explicit @@ -32,9 +31,10 @@ * \pre \c Buffer is the start of a buffer at least as big as \a * __llvm_profile_get_size_for_buffer_internal(). */ -int __llvm_profile_write_buffer_internal( - char *Buffer, const __llvm_profile_data *DataBegin, - const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, - const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd); +int __llvm_profile_write_buffer_internal(char *Buffer, + const __llvm_profile_data *DataBegin, + const __llvm_profile_data *DataEnd, + const uint64_t *CountersBegin, + const uint64_t *CountersEnd); #endif Index: lib/profile/InstrProfilingPlatformDarwin.c =================================================================== --- lib/profile/InstrProfilingPlatformDarwin.c +++ lib/profile/InstrProfilingPlatformDarwin.c @@ -16,10 +16,6 @@ __attribute__((visibility("hidden"))) extern __llvm_profile_data DataEnd __asm("section$end$__DATA$__llvm_prf_data"); __attribute__((visibility("hidden"))) -extern char NamesStart __asm("section$start$__DATA$__llvm_prf_names"); -__attribute__((visibility("hidden"))) -extern char NamesEnd __asm("section$end$__DATA$__llvm_prf_names"); -__attribute__((visibility("hidden"))) extern uint64_t CountersStart __asm("section$start$__DATA$__llvm_prf_cnts"); __attribute__((visibility("hidden"))) extern uint64_t CountersEnd __asm("section$end$__DATA$__llvm_prf_cnts"); @@ -33,10 +29,6 @@ return &DataEnd; } __attribute__((visibility("hidden"))) -const char *__llvm_profile_begin_names(void) { return &NamesStart; } -__attribute__((visibility("hidden"))) -const char *__llvm_profile_end_names(void) { return &NamesEnd; } -__attribute__((visibility("hidden"))) uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart; } __attribute__((visibility("hidden"))) uint64_t *__llvm_profile_end_counters(void) { return &CountersEnd; } Index: lib/profile/InstrProfilingPlatformOther.c =================================================================== --- lib/profile/InstrProfilingPlatformOther.c +++ lib/profile/InstrProfilingPlatformOther.c @@ -14,8 +14,6 @@ static const __llvm_profile_data *DataFirst = NULL; static const __llvm_profile_data *DataLast = NULL; -static const char *NamesFirst = NULL; -static const char *NamesLast = NULL; static uint64_t *CountersFirst = NULL; static uint64_t *CountersLast = NULL; @@ -33,8 +31,6 @@ if (!DataFirst) { DataFirst = Data; DataLast = Data + 1; - NamesFirst = Data->Name; - NamesLast = Data->Name + Data->NameSize; CountersFirst = Data->Counters; CountersLast = Data->Counters + Data->NumCounters; return; @@ -43,14 +39,12 @@ #define UPDATE_FIRST(First, New) \ First = New < First ? New : First UPDATE_FIRST(DataFirst, Data); - UPDATE_FIRST(NamesFirst, Data->Name); UPDATE_FIRST(CountersFirst, Data->Counters); #undef UPDATE_FIRST #define UPDATE_LAST(Last, New) \ Last = New > Last ? New : Last UPDATE_LAST(DataLast, Data + 1); - UPDATE_LAST(NamesLast, Data->Name + Data->NameSize); UPDATE_LAST(CountersLast, Data->Counters + Data->NumCounters); #undef UPDATE_LAST } @@ -64,10 +58,6 @@ return DataLast; } __attribute__((visibility("hidden"))) -const char *__llvm_profile_begin_names(void) { return NamesFirst; } -__attribute__((visibility("hidden"))) -const char *__llvm_profile_end_names(void) { return NamesLast; } -__attribute__((visibility("hidden"))) uint64_t *__llvm_profile_begin_counters(void) { return CountersFirst; } __attribute__((visibility("hidden"))) uint64_t *__llvm_profile_end_counters(void) { return CountersLast; } Index: test/Instrumentation/InstrProfiling/PR23499.ll =================================================================== --- test/Instrumentation/InstrProfiling/PR23499.ll +++ test/Instrumentation/InstrProfiling/PR23499.ll @@ -1,21 +1,22 @@ ;; Check that data associated with linkonce odr functions are placed in ;; the same comdat section as their associated function. -; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -instrprof -S | FileCheck %s -; RUN: opt < %s -mtriple=x86_64-unknown-linux -instrprof -S | FileCheck %s +; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -instrprof -S | FileCheck %s -check-prefix=MACHO +; RUN: opt < %s -mtriple=x86_64-unknown-linux -instrprof -S | FileCheck %s -check-prefix=ELF $_Z3barIvEvv = comdat any -@__llvm_profile_name__Z3barIvEvv = linkonce_odr hidden constant [11 x i8] c"_Z3barIvEvv", align 1 +@__llvm_prf_nm__Z3barIvEvv = linkonce_odr hidden constant [11 x i8] c"_Z3barIvEvv", align 1 -; CHECK: @__llvm_profile_name__Z3barIvEvv = linkonce_odr hidden constant [11 x i8] c"_Z3barIvEvv", section "{{.*}}__llvm_prf_names", comdat($__llvm_profile_vars__Z3barIvEvv), align 1 -; CHECK: @__llvm_profile_counters__Z3barIvEvv = linkonce_odr hidden global [1 x i64] zeroinitializer, section "{{.*}}__llvm_prf_cnts", comdat($__llvm_profile_vars__Z3barIvEvv), align 8 -; CHECK: @__llvm_profile_data__Z3barIvEvv = linkonce_odr hidden constant { i32, i32, i64, i8*, i64* } { i32 11, i32 1, i64 0, i8* getelementptr inbounds ([11 x i8], [11 x i8]* @__llvm_profile_name__Z3barIvEvv, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__llvm_profile_counters__Z3barIvEvv, i32 0, i32 0) }, section "{{.*}}__llvm_prf_data", comdat($__llvm_profile_vars__Z3barIvEvv), align 8 +; CHECK: @__llvm_prf_nm__Z3barIvEvv = extern_weak hidden constant [11 x i8] c"_Z3barIvEvv", align 1 +; CHECK: @__llvm_prf_cnts__Z3barIvEvv = linkonce_odr hidden global [1 x i64] zeroinitializer, section "{{.*}}__llvm_prf_cnts", comdat($__llvm_prf_vars__Z3barIvEvv), align 8 +; ELF: @__llvm_prf_data__Z3barIvEvv = linkonce_odr hidden constant { i64, i64, i64*, i32 } { i64 4947693190065689389, i64 0, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__llvm_prf_cnts__Z3barIvEvv, i32 0, i32 0), i32 1 }, section "__llvm_prf_data", comdat($__llvm_prf_vars__Z3barIvEvv), align 8 +; MACHO: @__llvm_prf_data__Z3barIvEvv = linkonce_odr hidden constant { i64, i64, i64*, i32 } { i64 4947693190065689389, i64 0, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__llvm_prf_cnts__Z3barIvEvv, i32 0, i32 0), i32 1 }, section "__DATA,__llvm_prf_data", comdat($__llvm_prf_vars__Z3barIvEvv), align 8 declare void @llvm.instrprof.increment(i8*, i64, i32, i32) #1 define linkonce_odr void @_Z3barIvEvv() comdat { entry: - call void @llvm.instrprof.increment(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @__llvm_profile_name__Z3barIvEvv, i32 0, i32 0), i64 0, i32 1, i32 0) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @__llvm_prf_nm__Z3barIvEvv, i32 0, i32 0), i64 0, i32 1, i32 0) ret void } Index: test/Instrumentation/InstrProfiling/linkage.ll =================================================================== --- test/Instrumentation/InstrProfiling/linkage.ll +++ test/Instrumentation/InstrProfiling/linkage.ll @@ -3,36 +3,36 @@ ; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -instrprof -S | FileCheck %s ; RUN: opt < %s -mtriple=x86_64-unknown-linux -instrprof -S | FileCheck %s -@__llvm_profile_name_foo = hidden constant [3 x i8] c"foo" -@__llvm_profile_name_foo_weak = weak hidden constant [8 x i8] c"foo_weak" -@"__llvm_profile_name_linkage.ll:foo_internal" = internal constant [23 x i8] c"linkage.ll:foo_internal" -@__llvm_profile_name_foo_inline = linkonce_odr hidden constant [10 x i8] c"foo_inline" +@__llvm_prf_nm_foo = hidden constant [3 x i8] c"foo" +@__llvm_prf_nm_foo_weak = weak hidden constant [8 x i8] c"foo_weak" +@"__llvm_prf_nm_linkage.ll:foo_internal" = internal constant [23 x i8] c"linkage.ll:foo_internal" +@__llvm_prf_nm_foo_inline = linkonce_odr hidden constant [10 x i8] c"foo_inline" -; CHECK: @__llvm_profile_counters_foo = hidden global -; CHECK: @__llvm_profile_data_foo = hidden constant +; CHECK: @__llvm_prf_cnts_foo = hidden global +; CHECK: @__llvm_prf_data_foo = hidden constant define void @foo() { - call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64 0, i32 1, i32 0) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_prf_nm_foo, i32 0, i32 0), i64 0, i32 1, i32 0) ret void } -; CHECK: @__llvm_profile_counters_foo_weak = weak hidden global -; CHECK: @__llvm_profile_data_foo_weak = weak hidden constant +; CHECK: @__llvm_prf_cnts_foo_weak = weak hidden global +; CHECK: @__llvm_prf_data_foo_weak = weak hidden constant define weak void @foo_weak() { - call void @llvm.instrprof.increment(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @__llvm_profile_name_foo_weak, i32 0, i32 0), i64 0, i32 1, i32 0) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @__llvm_prf_nm_foo_weak, i32 0, i32 0), i64 0, i32 1, i32 0) ret void } -; CHECK: @"__llvm_profile_counters_linkage.ll:foo_internal" = internal global -; CHECK: @"__llvm_profile_data_linkage.ll:foo_internal" = internal constant +; CHECK: @"__llvm_prf_cnts_linkage.ll:foo_internal" = internal global +; CHECK: @"__llvm_prf_data_linkage.ll:foo_internal" = internal constant define internal void @foo_internal() { - call void @llvm.instrprof.increment(i8* getelementptr inbounds ([23 x i8], [23 x i8]* @"__llvm_profile_name_linkage.ll:foo_internal", i32 0, i32 0), i64 0, i32 1, i32 0) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([23 x i8], [23 x i8]* @"__llvm_prf_nm_linkage.ll:foo_internal", i32 0, i32 0), i64 0, i32 1, i32 0) ret void } -; CHECK: @__llvm_profile_counters_foo_inline = linkonce_odr hidden global -; CHECK: @__llvm_profile_data_foo_inline = linkonce_odr hidden constant +; CHECK: @__llvm_prf_cnts_foo_inline = linkonce_odr hidden global +; CHECK: @__llvm_prf_data_foo_inline = linkonce_odr hidden constant define linkonce_odr void @foo_inline() { - call void @llvm.instrprof.increment(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @__llvm_profile_name_foo_inline, i32 0, i32 0), i64 0, i32 1, i32 0) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @__llvm_prf_nm_foo_inline, i32 0, i32 0), i64 0, i32 1, i32 0) ret void } Index: test/Instrumentation/InstrProfiling/platform.ll =================================================================== --- test/Instrumentation/InstrProfiling/platform.ll +++ test/Instrumentation/InstrProfiling/platform.ll @@ -3,17 +3,17 @@ ; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -instrprof -S | FileCheck %s -check-prefix=MACHO ; RUN: opt < %s -mtriple=x86_64-unknown-linux -instrprof -S | FileCheck %s -check-prefix=ELF -@__llvm_profile_name_foo = hidden constant [3 x i8] c"foo" -; MACHO: @__llvm_profile_name_foo = hidden constant [3 x i8] c"foo", section "__DATA,__llvm_prf_names", align 1 -; ELF: @__llvm_profile_name_foo = hidden constant [3 x i8] c"foo", section "__llvm_prf_names", align 1 +@__llvm_prf_nm_foo = hidden constant [3 x i8] c"foo" +; MACHO: @__llvm_prf_nm_foo = extern_weak hidden constant [3 x i8] c"foo" +; ELF: @__llvm_prf_nm_foo = extern_weak hidden constant [3 x i8] c"foo" -; MACHO: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 -; ELF: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__llvm_prf_cnts", align 8 +; MACHO: @__llvm_prf_cnts_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +; ELF: @__llvm_prf_cnts_foo = hidden global [1 x i64] zeroinitializer, section "__llvm_prf_cnts", align 8 -; MACHO: @__llvm_profile_data_foo = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 -; ELF: @__llvm_profile_data_foo = hidden constant {{.*}}, section "__llvm_prf_data", align 8 +; MACHO: @__llvm_prf_data_foo = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 +; ELF: @__llvm_prf_data_foo = hidden constant {{.*}}, section "__llvm_prf_data", align 8 define void @foo() { - call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64 0, i32 1, i32 0) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_prf_nm_foo, i32 0, i32 0), i64 0, i32 1, i32 0) ret void } Index: test/Instrumentation/InstrProfiling/profiling.ll =================================================================== --- test/Instrumentation/InstrProfiling/profiling.ll +++ test/Instrumentation/InstrProfiling/profiling.ll @@ -2,37 +2,37 @@ target triple = "x86_64-apple-macosx10.10.0" -@__llvm_profile_name_foo = hidden constant [3 x i8] c"foo" -; CHECK: @__llvm_profile_name_foo = hidden constant [3 x i8] c"foo", section "__DATA,__llvm_prf_names", align 1 -@__llvm_profile_name_bar = hidden constant [4 x i8] c"bar\00" -; CHECK: @__llvm_profile_name_bar = hidden constant [4 x i8] c"bar\00", section "__DATA,__llvm_prf_names", align 1 -@baz_prof_name = hidden constant [3 x i8] c"baz" -; CHECK: @baz_prof_name = hidden constant [3 x i8] c"baz", section "__DATA,__llvm_prf_names", align 1 +@__llvm_prf_nm_foo = hidden constant [3 x i8] c"foo" +; CHECK: @__llvm_prf_nm_foo = extern_weak hidden constant [3 x i8] c"foo" +@__llvm_prf_nm_bar = hidden constant [4 x i8] c"bar\00" +; CHECK: @__llvm_prf_nm_bar = extern_weak hidden constant [4 x i8] c"bar\00" +@__llvm_prf_nm_baz = hidden constant [3 x i8] c"baz" +; CHECK: @__llvm_prf_nm_baz = extern_weak hidden constant [3 x i8] c"baz" -; CHECK: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 -; CHECK: @__llvm_profile_data_foo = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 +; CHECK: @__llvm_prf_cnts_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +; CHECK: @__llvm_prf_data_foo = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 define void @foo() { - call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64 0, i32 1, i32 0) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_prf_nm_foo, i32 0, i32 0), i64 0, i32 1, i32 0) ret void } -; CHECK: @__llvm_profile_counters_bar = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 -; CHECK: @__llvm_profile_data_bar = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 +; CHECK: @__llvm_prf_cnts_bar = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +; CHECK: @__llvm_prf_data_bar = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 define void @bar() { - call void @llvm.instrprof.increment(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @__llvm_profile_name_bar, i32 0, i32 0), i64 0, i32 1, i32 0) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @__llvm_prf_nm_bar, i32 0, i32 0), i64 0, i32 1, i32 0) ret void } -; CHECK: @__llvm_profile_counters_baz = hidden global [3 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 -; CHECK: @__llvm_profile_data_baz = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 +; CHECK: @__llvm_prf_cnts_baz = hidden global [3 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +; CHECK: @__llvm_prf_data_baz = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 define void @baz() { - call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @baz_prof_name, i32 0, i32 0), i64 0, i32 3, i32 0) - call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @baz_prof_name, i32 0, i32 0), i64 0, i32 3, i32 1) - call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @baz_prof_name, i32 0, i32 0), i64 0, i32 3, i32 2) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_prf_nm_baz, i32 0, i32 0), i64 0, i32 3, i32 0) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_prf_nm_baz, i32 0, i32 0), i64 0, i32 3, i32 1) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_prf_nm_baz, i32 0, i32 0), i64 0, i32 3, i32 2) ret void } declare void @llvm.instrprof.increment(i8*, i64, i32, i32) ; CHECK: @__llvm_profile_runtime = external global i32 -; CHECK: @llvm.used = appending global {{.*}} @__llvm_profile_data_foo {{.*}} @__llvm_profile_data_bar {{.*}} @__llvm_profile_data_baz {{.*}} section "llvm.metadata" +; CHECK: @llvm.used = appending global {{.*}} @__llvm_prf_data_foo {{.*}} @__llvm_prf_data_bar {{.*}} @__llvm_prf_data_baz {{.*}} section "llvm.metadata" Index: test/tools/llvm-profdata/c-general.test =================================================================== --- test/tools/llvm-profdata/c-general.test +++ test/tools/llvm-profdata/c-general.test @@ -10,15 +10,15 @@ REGENERATE: $ LLVM_PROFILE_FILE=$TESTDIR/Inputs/c-general.profraw ./a.out RUN: llvm-profdata show %p/Inputs/c-general.profraw -o - | FileCheck %s -check-prefix=CHECK -RUN: llvm-profdata show %p/Inputs/c-general.profraw -o - --function=switches | FileCheck %s -check-prefix=SWITCHES -check-prefix=CHECK +RUN: llvm-profdata show %p/Inputs/c-general.profraw -o - -instr-binary=%p/Inputs/c-general.bin --function=switches | FileCheck %s -check-prefix=SWITCHES -check-prefix=CHECK SWITCHES-LABEL: Counters: SWITCHES-NEXT: switches: -SWITCHES-NEXT: Hash: 0x0000000000000013 +SWITCHES-NEXT: Hash: 0x2618e4f23f2e8daa SWITCHES-NEXT: Counters: 19 SWITCHES-NEXT: Function count: 1 SWITCHES-LABEL: Functions shown: 1 -CHECK-LABEL: Total functions: 11 +CHECK-LABEL: Total functions: 12 CHECK-NEXT: Maximum function count: 1 CHECK-NEXT: Maximum internal block count: 100 Index: test/tools/llvm-profdata/general.proftext =================================================================== --- test/tools/llvm-profdata/general.proftext +++ test/tools/llvm-profdata/general.proftext @@ -50,12 +50,6 @@ # NOSUCHFUNC-NOT: Counters: # NOSUCHFUNC: Functions shown: 0 -# RUN: llvm-profdata show %t.profdata --function _ | FileCheck %s -check-prefix=SOMEFUNCS -# SOMEFUNCS: Counters: -# SOMEFUNCS: function_count_only: -# SOMEFUNCS: large_numbers: -# SOMEFUNCS: Functions shown: 3 - # RUN: llvm-profdata show %t.profdata | FileCheck %s -check-prefix=SUMMARY # SUMMARY-NOT: Counters: # SUMMARY-NOT: Functions shown: Index: test/tools/llvm-profdata/multiple-inputs.test =================================================================== --- test/tools/llvm-profdata/multiple-inputs.test +++ test/tools/llvm-profdata/multiple-inputs.test @@ -4,7 +4,6 @@ RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s --check-prefix=FOO3 RUN: llvm-profdata merge %p/Inputs/foo3-2.proftext %p/Inputs/foo3-1.proftext -o %t RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s --check-prefix=FOO3 -FOO3: foo: FOO3: Counters: 3 FOO3: Function count: 8 FOO3: Block counts: [7, 6] @@ -14,7 +13,6 @@ RUN: llvm-profdata merge %p/Inputs/empty.proftext %p/Inputs/foo3-1.proftext -o %t RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s --check-prefix=FOO3EMPTY -FOO3EMPTY: foo: FOO3EMPTY: Counters: 3 FOO3EMPTY: Function count: 1 FOO3EMPTY: Block counts: [2, 3] @@ -24,11 +22,9 @@ RUN: llvm-profdata merge %p/Inputs/foo3-1.proftext %p/Inputs/foo3bar3-1.proftext -o %t RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s --check-prefix=FOO3FOO3BAR3 -FOO3FOO3BAR3: foo: FOO3FOO3BAR3: Counters: 3 FOO3FOO3BAR3: Function count: 3 FOO3FOO3BAR3: Block counts: [5, 8] -FOO3FOO3BAR3: bar: FOO3FOO3BAR3: Counters: 3 FOO3FOO3BAR3: Function count: 7 FOO3FOO3BAR3: Block counts: [11, 13] @@ -38,11 +34,9 @@ RUN: llvm-profdata merge %p/Inputs/foo3-1.proftext %p/Inputs/bar3-1.proftext -o %t RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s --check-prefix=DISJOINT -DISJOINT: foo: DISJOINT: Counters: 3 DISJOINT: Function count: 1 DISJOINT: Block counts: [2, 3] -DISJOINT: bar: DISJOINT: Counters: 3 DISJOINT: Function count: 1 DISJOINT: Block counts: [2, 3] Index: tools/llvm-profdata/llvm-profdata.cpp =================================================================== --- tools/llvm-profdata/llvm-profdata.cpp +++ tools/llvm-profdata/llvm-profdata.cpp @@ -13,6 +13,8 @@ #include "llvm/ADT/StringRef.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/Object/MachOUniversal.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/ProfileData/InstrProfWriter.h" #include "llvm/ProfileData/SampleProfReader.h" @@ -28,6 +30,7 @@ #include "llvm/Support/raw_ostream.h" using namespace llvm; +using namespace object; static void exitWithError(const Twine &Message, StringRef Whence = "") { errs() << "error: "; @@ -132,7 +135,52 @@ return 0; } -static int showInstrProfile(std::string Filename, bool ShowCounts, +static void populateSymtab(std::string binFilename, std::string Arch, + std::unique_ptr &ProfSyms) { + if (binFilename.empty()) + return; + auto Buf = MemoryBuffer::getFileOrSTDIN(binFilename); + if (Buf.getError()) { + errs() << "warning: -instr-binary specifies an invalid file\n"; + return; + } + + MemoryBufferRef ObjectBuffer = Buf.get()->getMemBufferRef(); + auto BinOrErr = object::createBinary(ObjectBuffer); + if (BinOrErr.getError()) { + errs() << "warning: -instr-binary specifies an invalid object file\n"; + return; + } + 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()) { + errs() << "warning: -instr-binary specifies an invalid file\n"; + return; + } + 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()) { + errs() << "warning: -instr-binary specifies an invalid file\n"; + return; + } + } else { + // We can only handle object files. + errs() << "warning: -instr-binary specifies an invalid file\n"; + return; + } + + ProfSyms.reset(new ProfSymtab(OF->symbols())); +} + +static int showInstrProfile(std::string Filename, std::string binFilename, + std::string Arch, bool ShowCounts, bool ShowIndirectCallTargets, bool ShowAllFunctions, std::string ShowFunction, raw_fd_ostream &OS) { auto ReaderOrErr = InstrProfReader::create(Filename); @@ -140,12 +188,23 @@ exitWithError(EC.message(), Filename); auto Reader = std::move(ReaderOrErr.get()); + std::unique_ptr ProfSyms; + populateSymtab(binFilename, Arch, ProfSyms); uint64_t MaxFunctionCount = 0, MaxBlockCount = 0; size_t ShownFunctions = 0, TotalFunctions = 0; for (const auto &Func : *Reader) { + StringRef FuncName = Func.Name; + if (FuncName.empty() && ProfSyms) + ProfSyms->getFunctionName(Func.NameKey, 0, FuncName); + uint64_t ShowFunctionKey = 0; + if (!ShowFunction.empty()) + ShowFunctionKey = IndexedInstrProf::ComputeHash( + IndexedInstrProf::HashType, ShowFunction); bool Show = - ShowAllFunctions || (!ShowFunction.empty() && - Func.Name.find(ShowFunction) != Func.Name.npos); + ShowAllFunctions || + (!ShowFunction.empty() && + ((!FuncName.empty() && FuncName.find(ShowFunction) != FuncName.npos) || + ShowFunctionKey == Func.NameKey)); ++TotalFunctions; assert(Func.Counts.size() > 0 && "function missing entry counter"); @@ -156,9 +215,11 @@ if (!ShownFunctions) OS << "Counters:\n"; ++ShownFunctions; - - OS << " " << Func.Name << ":\n" - << " Hash: " << format("0x%016" PRIx64, Func.Hash) << "\n" + if (FuncName.empty()) + OS << " " << format("%" PRIx64, Func.NameKey) << ":\n"; + else + OS << " " << FuncName << ":\n"; + OS << " Hash: " << format("0x%016" PRIx64, Func.Hash) << "\n" << " Counters: " << Func.Counts.size() << "\n" << " Function count: " << Func.Counts[0] << "\n"; if (ShowIndirectCallTargets) @@ -232,6 +293,12 @@ cl::opt ShowFunction("function", cl::desc("Details for matching functions")); + cl::opt BinFilename( + "instr-binary", + cl::desc("Path of unstripped binary with instrumentation")); + cl::opt Arch("arch", + cl::desc("architecture of the profiled binary")); + cl::opt OutputFilename("output", cl::value_desc("output"), cl::init("-"), cl::desc("Output file")); cl::alias OutputFilenameA("o", cl::desc("Alias for --output"), @@ -255,8 +322,9 @@ errs() << "warning: -function argument ignored: showing all functions\n"; if (ProfileKind == instr) - return showInstrProfile(Filename, ShowCounts, ShowIndirectCallTargets, - ShowAllFunctions, ShowFunction, OS); + return showInstrProfile(Filename, BinFilename, Arch, ShowCounts, + ShowIndirectCallTargets, ShowAllFunctions, + ShowFunction, OS); else return showSampleProfile(Filename, ShowCounts, ShowAllFunctions, ShowFunction, OS); Index: unittests/ProfileData/InstrProfTest.cpp =================================================================== --- unittests/ProfileData/InstrProfTest.cpp +++ unittests/ProfileData/InstrProfTest.cpp @@ -57,7 +57,9 @@ auto I = Reader->begin(), E = Reader->end(); ASSERT_TRUE(I != E); - ASSERT_EQ(StringRef("foo"), I->Name); + ASSERT_EQ(IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType, + StringRef("foo")), + I->NameKey); ASSERT_EQ(0x1234U, I->Hash); ASSERT_EQ(4U, I->Counts.size()); ASSERT_EQ(1U, I->Counts[0]);