10b57cec5SDimitry Andric //===- InstrProf.cpp - Instrumented profiling format support --------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file contains support for clang's instrumentation based PGO and 100b57cec5SDimitry Andric // coverage. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProf.h" 150b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 160b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 170b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 180b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 19fe6060f1SDimitry Andric #include "llvm/Config/config.h" 200b57cec5SDimitry Andric #include "llvm/IR/Constant.h" 210b57cec5SDimitry Andric #include "llvm/IR/Constants.h" 220b57cec5SDimitry Andric #include "llvm/IR/Function.h" 230b57cec5SDimitry Andric #include "llvm/IR/GlobalValue.h" 240b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h" 250b57cec5SDimitry Andric #include "llvm/IR/Instruction.h" 260b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h" 270b57cec5SDimitry Andric #include "llvm/IR/MDBuilder.h" 280b57cec5SDimitry Andric #include "llvm/IR/Metadata.h" 290b57cec5SDimitry Andric #include "llvm/IR/Module.h" 300b57cec5SDimitry Andric #include "llvm/IR/Type.h" 310b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfReader.h" 320b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 330b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 340b57cec5SDimitry Andric #include "llvm/Support/Compiler.h" 350b57cec5SDimitry Andric #include "llvm/Support/Compression.h" 36*0fca6ea1SDimitry Andric #include "llvm/Support/Debug.h" 370b57cec5SDimitry Andric #include "llvm/Support/Endian.h" 380b57cec5SDimitry Andric #include "llvm/Support/Error.h" 390b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 400b57cec5SDimitry Andric #include "llvm/Support/LEB128.h" 410b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 420b57cec5SDimitry Andric #include "llvm/Support/Path.h" 430b57cec5SDimitry Andric #include "llvm/Support/SwapByteOrder.h" 4406c3fb27SDimitry Andric #include "llvm/Support/VirtualFileSystem.h" 4506c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h" 460b57cec5SDimitry Andric #include <algorithm> 470b57cec5SDimitry Andric #include <cassert> 480b57cec5SDimitry Andric #include <cstddef> 490b57cec5SDimitry Andric #include <cstdint> 500b57cec5SDimitry Andric #include <cstring> 510b57cec5SDimitry Andric #include <memory> 520b57cec5SDimitry Andric #include <string> 530b57cec5SDimitry Andric #include <system_error> 5481ad6265SDimitry Andric #include <type_traits> 550b57cec5SDimitry Andric #include <utility> 560b57cec5SDimitry Andric #include <vector> 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric using namespace llvm; 590b57cec5SDimitry Andric 60*0fca6ea1SDimitry Andric #define DEBUG_TYPE "instrprof" 61*0fca6ea1SDimitry Andric 620b57cec5SDimitry Andric static cl::opt<bool> StaticFuncFullModulePrefix( 630b57cec5SDimitry Andric "static-func-full-module-prefix", cl::init(true), cl::Hidden, 640b57cec5SDimitry Andric cl::desc("Use full module build paths in the profile counter names for " 650b57cec5SDimitry Andric "static functions.")); 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric // This option is tailored to users that have different top-level directory in 680b57cec5SDimitry Andric // profile-gen and profile-use compilation. Users need to specific the number 690b57cec5SDimitry Andric // of levels to strip. A value larger than the number of directories in the 700b57cec5SDimitry Andric // source file will strip all the directory names and only leave the basename. 710b57cec5SDimitry Andric // 720b57cec5SDimitry Andric // Note current ThinLTO module importing for the indirect-calls assumes 730b57cec5SDimitry Andric // the source directory name not being stripped. A non-zero option value here 740b57cec5SDimitry Andric // can potentially prevent some inter-module indirect-call-promotions. 750b57cec5SDimitry Andric static cl::opt<unsigned> StaticFuncStripDirNamePrefix( 760b57cec5SDimitry Andric "static-func-strip-dirname-prefix", cl::init(0), cl::Hidden, 770b57cec5SDimitry Andric cl::desc("Strip specified level of directory name from source path in " 780b57cec5SDimitry Andric "the profile counter name for static functions.")); 790b57cec5SDimitry Andric 80349cc55cSDimitry Andric static std::string getInstrProfErrString(instrprof_error Err, 81349cc55cSDimitry Andric const std::string &ErrMsg = "") { 82349cc55cSDimitry Andric std::string Msg; 83349cc55cSDimitry Andric raw_string_ostream OS(Msg); 84349cc55cSDimitry Andric 850b57cec5SDimitry Andric switch (Err) { 860b57cec5SDimitry Andric case instrprof_error::success: 87349cc55cSDimitry Andric OS << "success"; 88349cc55cSDimitry Andric break; 890b57cec5SDimitry Andric case instrprof_error::eof: 90349cc55cSDimitry Andric OS << "end of File"; 91349cc55cSDimitry Andric break; 920b57cec5SDimitry Andric case instrprof_error::unrecognized_format: 93349cc55cSDimitry Andric OS << "unrecognized instrumentation profile encoding format"; 94349cc55cSDimitry Andric break; 950b57cec5SDimitry Andric case instrprof_error::bad_magic: 96349cc55cSDimitry Andric OS << "invalid instrumentation profile data (bad magic)"; 97349cc55cSDimitry Andric break; 980b57cec5SDimitry Andric case instrprof_error::bad_header: 99349cc55cSDimitry Andric OS << "invalid instrumentation profile data (file header is corrupt)"; 100349cc55cSDimitry Andric break; 1010b57cec5SDimitry Andric case instrprof_error::unsupported_version: 102349cc55cSDimitry Andric OS << "unsupported instrumentation profile format version"; 103349cc55cSDimitry Andric break; 1040b57cec5SDimitry Andric case instrprof_error::unsupported_hash_type: 105349cc55cSDimitry Andric OS << "unsupported instrumentation profile hash type"; 106349cc55cSDimitry Andric break; 1070b57cec5SDimitry Andric case instrprof_error::too_large: 108349cc55cSDimitry Andric OS << "too much profile data"; 109349cc55cSDimitry Andric break; 1100b57cec5SDimitry Andric case instrprof_error::truncated: 111349cc55cSDimitry Andric OS << "truncated profile data"; 112349cc55cSDimitry Andric break; 1130b57cec5SDimitry Andric case instrprof_error::malformed: 114349cc55cSDimitry Andric OS << "malformed instrumentation profile data"; 115349cc55cSDimitry Andric break; 1165f757f3fSDimitry Andric case instrprof_error::missing_correlation_info: 1175f757f3fSDimitry Andric OS << "debug info/binary for correlation is required"; 1180eae32dcSDimitry Andric break; 1195f757f3fSDimitry Andric case instrprof_error::unexpected_correlation_info: 1205f757f3fSDimitry Andric OS << "debug info/binary for correlation is not necessary"; 1210eae32dcSDimitry Andric break; 1220eae32dcSDimitry Andric case instrprof_error::unable_to_correlate_profile: 1230eae32dcSDimitry Andric OS << "unable to correlate profile"; 1240eae32dcSDimitry Andric break; 125fe6060f1SDimitry Andric case instrprof_error::invalid_prof: 126349cc55cSDimitry Andric OS << "invalid profile created. Please file a bug " 127fe6060f1SDimitry Andric "at: " BUG_REPORT_URL 128fe6060f1SDimitry Andric " and include the profraw files that caused this error."; 129349cc55cSDimitry Andric break; 1300b57cec5SDimitry Andric case instrprof_error::unknown_function: 131349cc55cSDimitry Andric OS << "no profile data available for function"; 132349cc55cSDimitry Andric break; 1330b57cec5SDimitry Andric case instrprof_error::hash_mismatch: 134349cc55cSDimitry Andric OS << "function control flow change detected (hash mismatch)"; 135349cc55cSDimitry Andric break; 1360b57cec5SDimitry Andric case instrprof_error::count_mismatch: 137349cc55cSDimitry Andric OS << "function basic block count change detected (counter mismatch)"; 138349cc55cSDimitry Andric break; 1395f757f3fSDimitry Andric case instrprof_error::bitmap_mismatch: 1405f757f3fSDimitry Andric OS << "function bitmap size change detected (bitmap size mismatch)"; 1415f757f3fSDimitry Andric break; 1420b57cec5SDimitry Andric case instrprof_error::counter_overflow: 143349cc55cSDimitry Andric OS << "counter overflow"; 144349cc55cSDimitry Andric break; 1450b57cec5SDimitry Andric case instrprof_error::value_site_count_mismatch: 146349cc55cSDimitry Andric OS << "function value site count change detected (counter mismatch)"; 147349cc55cSDimitry Andric break; 1480b57cec5SDimitry Andric case instrprof_error::compress_failed: 149349cc55cSDimitry Andric OS << "failed to compress data (zlib)"; 150349cc55cSDimitry Andric break; 1510b57cec5SDimitry Andric case instrprof_error::uncompress_failed: 152349cc55cSDimitry Andric OS << "failed to uncompress data (zlib)"; 153349cc55cSDimitry Andric break; 1540b57cec5SDimitry Andric case instrprof_error::empty_raw_profile: 155349cc55cSDimitry Andric OS << "empty raw profile file"; 156349cc55cSDimitry Andric break; 1570b57cec5SDimitry Andric case instrprof_error::zlib_unavailable: 158349cc55cSDimitry Andric OS << "profile uses zlib compression but the profile reader was built " 159fe6060f1SDimitry Andric "without zlib support"; 160349cc55cSDimitry Andric break; 16106c3fb27SDimitry Andric case instrprof_error::raw_profile_version_mismatch: 16206c3fb27SDimitry Andric OS << "raw profile version mismatch"; 16306c3fb27SDimitry Andric break; 1645f757f3fSDimitry Andric case instrprof_error::counter_value_too_large: 1655f757f3fSDimitry Andric OS << "excessively large counter value suggests corrupted profile data"; 1665f757f3fSDimitry Andric break; 1670b57cec5SDimitry Andric } 168349cc55cSDimitry Andric 169349cc55cSDimitry Andric // If optional error message is not empty, append it to the message. 170349cc55cSDimitry Andric if (!ErrMsg.empty()) 171349cc55cSDimitry Andric OS << ": " << ErrMsg; 172349cc55cSDimitry Andric 173349cc55cSDimitry Andric return OS.str(); 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric namespace { 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric // FIXME: This class is only here to support the transition to llvm::Error. It 1790b57cec5SDimitry Andric // will be removed once this transition is complete. Clients should prefer to 1800b57cec5SDimitry Andric // deal with the Error value directly, rather than converting to error_code. 1810b57cec5SDimitry Andric class InstrProfErrorCategoryType : public std::error_category { 1820b57cec5SDimitry Andric const char *name() const noexcept override { return "llvm.instrprof"; } 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric std::string message(int IE) const override { 1850b57cec5SDimitry Andric return getInstrProfErrString(static_cast<instrprof_error>(IE)); 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric }; 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric } // end anonymous namespace 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric const std::error_category &llvm::instrprof_category() { 192753f127fSDimitry Andric static InstrProfErrorCategoryType ErrorCategory; 193753f127fSDimitry Andric return ErrorCategory; 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric namespace { 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric const char *InstrProfSectNameCommon[] = { 1990b57cec5SDimitry Andric #define INSTR_PROF_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) \ 2000b57cec5SDimitry Andric SectNameCommon, 2010b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfData.inc" 2020b57cec5SDimitry Andric }; 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric const char *InstrProfSectNameCoff[] = { 2050b57cec5SDimitry Andric #define INSTR_PROF_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) \ 2060b57cec5SDimitry Andric SectNameCoff, 2070b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfData.inc" 2080b57cec5SDimitry Andric }; 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric const char *InstrProfSectNamePrefix[] = { 2110b57cec5SDimitry Andric #define INSTR_PROF_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) \ 2120b57cec5SDimitry Andric Prefix, 2130b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfData.inc" 2140b57cec5SDimitry Andric }; 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric } // namespace 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric namespace llvm { 2190b57cec5SDimitry Andric 2205ffd83dbSDimitry Andric cl::opt<bool> DoInstrProfNameCompression( 2215ffd83dbSDimitry Andric "enable-name-compression", 2225ffd83dbSDimitry Andric cl::desc("Enable name/filename string compression"), cl::init(true)); 2235ffd83dbSDimitry Andric 224*0fca6ea1SDimitry Andric cl::opt<bool> EnableVTableValueProfiling( 225*0fca6ea1SDimitry Andric "enable-vtable-value-profiling", cl::init(false), 226*0fca6ea1SDimitry Andric cl::desc("If true, the virtual table address will be instrumented to know " 227*0fca6ea1SDimitry Andric "the types of a C++ pointer. The information is used in indirect " 228*0fca6ea1SDimitry Andric "call promotion to do selective vtable-based comparison.")); 229*0fca6ea1SDimitry Andric 230*0fca6ea1SDimitry Andric cl::opt<bool> EnableVTableProfileUse( 231*0fca6ea1SDimitry Andric "enable-vtable-profile-use", cl::init(false), 232*0fca6ea1SDimitry Andric cl::desc("If ThinLTO and WPD is enabled and this option is true, vtable " 233*0fca6ea1SDimitry Andric "profiles will be used by ICP pass for more efficient indirect " 234*0fca6ea1SDimitry Andric "call sequence. If false, type profiles won't be used.")); 235*0fca6ea1SDimitry Andric 2360b57cec5SDimitry Andric std::string getInstrProfSectionName(InstrProfSectKind IPSK, 2370b57cec5SDimitry Andric Triple::ObjectFormatType OF, 2380b57cec5SDimitry Andric bool AddSegmentInfo) { 2390b57cec5SDimitry Andric std::string SectName; 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric if (OF == Triple::MachO && AddSegmentInfo) 2420b57cec5SDimitry Andric SectName = InstrProfSectNamePrefix[IPSK]; 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric if (OF == Triple::COFF) 2450b57cec5SDimitry Andric SectName += InstrProfSectNameCoff[IPSK]; 2460b57cec5SDimitry Andric else 2470b57cec5SDimitry Andric SectName += InstrProfSectNameCommon[IPSK]; 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric if (OF == Triple::MachO && IPSK == IPSK_data && AddSegmentInfo) 2500b57cec5SDimitry Andric SectName += ",regular,live_support"; 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric return SectName; 2530b57cec5SDimitry Andric } 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric std::string InstrProfError::message() const { 256349cc55cSDimitry Andric return getInstrProfErrString(Err, Msg); 2570b57cec5SDimitry Andric } 2580b57cec5SDimitry Andric 2590b57cec5SDimitry Andric char InstrProfError::ID = 0; 2600b57cec5SDimitry Andric 261cb14a3feSDimitry Andric std::string getPGOFuncName(StringRef Name, GlobalValue::LinkageTypes Linkage, 2620b57cec5SDimitry Andric StringRef FileName, 2630b57cec5SDimitry Andric uint64_t Version LLVM_ATTRIBUTE_UNUSED) { 264cb14a3feSDimitry Andric // Value names may be prefixed with a binary '1' to indicate 265cb14a3feSDimitry Andric // that the backend should not modify the symbols due to any platform 266cb14a3feSDimitry Andric // naming convention. Do not include that '1' in the PGO profile name. 267cb14a3feSDimitry Andric if (Name[0] == '\1') 268cb14a3feSDimitry Andric Name = Name.substr(1); 269cb14a3feSDimitry Andric 270cb14a3feSDimitry Andric std::string NewName = std::string(Name); 271cb14a3feSDimitry Andric if (llvm::GlobalValue::isLocalLinkage(Linkage)) { 272cb14a3feSDimitry Andric // For local symbols, prepend the main file name to distinguish them. 273cb14a3feSDimitry Andric // Do not include the full path in the file name since there's no guarantee 274cb14a3feSDimitry Andric // that it will stay the same, e.g., if the files are checked out from 275cb14a3feSDimitry Andric // version control in different locations. 276cb14a3feSDimitry Andric if (FileName.empty()) 277cb14a3feSDimitry Andric NewName = NewName.insert(0, "<unknown>:"); 278cb14a3feSDimitry Andric else 279cb14a3feSDimitry Andric NewName = NewName.insert(0, FileName.str() + ":"); 280cb14a3feSDimitry Andric } 281cb14a3feSDimitry Andric return NewName; 2820b57cec5SDimitry Andric } 2830b57cec5SDimitry Andric 2840b57cec5SDimitry Andric // Strip NumPrefix level of directory name from PathNameStr. If the number of 2850b57cec5SDimitry Andric // directory separators is less than NumPrefix, strip all the directories and 2860b57cec5SDimitry Andric // leave base file name only. 2870b57cec5SDimitry Andric static StringRef stripDirPrefix(StringRef PathNameStr, uint32_t NumPrefix) { 2880b57cec5SDimitry Andric uint32_t Count = NumPrefix; 2890b57cec5SDimitry Andric uint32_t Pos = 0, LastPos = 0; 290*0fca6ea1SDimitry Andric for (const auto &CI : PathNameStr) { 2910b57cec5SDimitry Andric ++Pos; 2920b57cec5SDimitry Andric if (llvm::sys::path::is_separator(CI)) { 2930b57cec5SDimitry Andric LastPos = Pos; 2940b57cec5SDimitry Andric --Count; 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric if (Count == 0) 2970b57cec5SDimitry Andric break; 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric return PathNameStr.substr(LastPos); 3000b57cec5SDimitry Andric } 3010b57cec5SDimitry Andric 3025f757f3fSDimitry Andric static StringRef getStrippedSourceFileName(const GlobalObject &GO) { 3035f757f3fSDimitry Andric StringRef FileName(GO.getParent()->getSourceFileName()); 3045f757f3fSDimitry Andric uint32_t StripLevel = StaticFuncFullModulePrefix ? 0 : (uint32_t)-1; 3055f757f3fSDimitry Andric if (StripLevel < StaticFuncStripDirNamePrefix) 3065f757f3fSDimitry Andric StripLevel = StaticFuncStripDirNamePrefix; 3075f757f3fSDimitry Andric if (StripLevel) 3085f757f3fSDimitry Andric FileName = stripDirPrefix(FileName, StripLevel); 3095f757f3fSDimitry Andric return FileName; 3105f757f3fSDimitry Andric } 3115f757f3fSDimitry Andric 3121db9f3b2SDimitry Andric // The PGO name has the format [<filepath>;]<mangled-name> where <filepath>; is 3131db9f3b2SDimitry Andric // provided if linkage is local and is used to discriminate possibly identical 3141db9f3b2SDimitry Andric // mangled names. ";" is used because it is unlikely to be found in either 3151db9f3b2SDimitry Andric // <filepath> or <mangled-name>. 3165f757f3fSDimitry Andric // 3175f757f3fSDimitry Andric // Older compilers used getPGOFuncName() which has the format 3181db9f3b2SDimitry Andric // [<filepath>:]<mangled-name>. This caused trouble for Objective-C functions 3191db9f3b2SDimitry Andric // which commonly have :'s in their names. We still need to compute this name to 3201db9f3b2SDimitry Andric // lookup functions from profiles built by older compilers. 3215f757f3fSDimitry Andric static std::string 3225f757f3fSDimitry Andric getIRPGONameForGlobalObject(const GlobalObject &GO, 3235f757f3fSDimitry Andric GlobalValue::LinkageTypes Linkage, 3245f757f3fSDimitry Andric StringRef FileName) { 3251db9f3b2SDimitry Andric return GlobalValue::getGlobalIdentifier(GO.getName(), Linkage, FileName); 3265f757f3fSDimitry Andric } 3275f757f3fSDimitry Andric 3285f757f3fSDimitry Andric static std::optional<std::string> lookupPGONameFromMetadata(MDNode *MD) { 3295f757f3fSDimitry Andric if (MD != nullptr) { 3305f757f3fSDimitry Andric StringRef S = cast<MDString>(MD->getOperand(0))->getString(); 3315f757f3fSDimitry Andric return S.str(); 3325f757f3fSDimitry Andric } 3335f757f3fSDimitry Andric return {}; 3345f757f3fSDimitry Andric } 3355f757f3fSDimitry Andric 3365f757f3fSDimitry Andric // Returns the PGO object name. This function has some special handling 3375f757f3fSDimitry Andric // when called in LTO optimization. The following only applies when calling in 3385f757f3fSDimitry Andric // LTO passes (when \c InLTO is true): LTO's internalization privatizes many 3395f757f3fSDimitry Andric // global linkage symbols. This happens after value profile annotation, but 3405f757f3fSDimitry Andric // those internal linkage functions should not have a source prefix. 3410b57cec5SDimitry Andric // Additionally, for ThinLTO mode, exported internal functions are promoted 3420b57cec5SDimitry Andric // and renamed. We need to ensure that the original internal PGO name is 3430b57cec5SDimitry Andric // used when computing the GUID that is compared against the profiled GUIDs. 3440b57cec5SDimitry Andric // To differentiate compiler generated internal symbols from original ones, 3450b57cec5SDimitry Andric // PGOFuncName meta data are created and attached to the original internal 3460b57cec5SDimitry Andric // symbols in the value profile annotation step 3470b57cec5SDimitry Andric // (PGOUseFunc::annotateIndirectCallSites). If a symbol does not have the meta 3480b57cec5SDimitry Andric // data, its original linkage must be non-internal. 3495f757f3fSDimitry Andric static std::string getIRPGOObjectName(const GlobalObject &GO, bool InLTO, 3505f757f3fSDimitry Andric MDNode *PGONameMetadata) { 3515f757f3fSDimitry Andric if (!InLTO) { 3525f757f3fSDimitry Andric auto FileName = getStrippedSourceFileName(GO); 3535f757f3fSDimitry Andric return getIRPGONameForGlobalObject(GO, GO.getLinkage(), FileName); 3545f757f3fSDimitry Andric } 3555f757f3fSDimitry Andric 3565f757f3fSDimitry Andric // In LTO mode (when InLTO is true), first check if there is a meta data. 3575f757f3fSDimitry Andric if (auto IRPGOFuncName = lookupPGONameFromMetadata(PGONameMetadata)) 3585f757f3fSDimitry Andric return *IRPGOFuncName; 3595f757f3fSDimitry Andric 3605f757f3fSDimitry Andric // If there is no meta data, the function must be a global before the value 3615f757f3fSDimitry Andric // profile annotation pass. Its current linkage may be internal if it is 3625f757f3fSDimitry Andric // internalized in LTO mode. 3635f757f3fSDimitry Andric return getIRPGONameForGlobalObject(GO, GlobalValue::ExternalLinkage, ""); 3645f757f3fSDimitry Andric } 3655f757f3fSDimitry Andric 3665f757f3fSDimitry Andric // Returns the IRPGO function name and does special handling when called 3675f757f3fSDimitry Andric // in LTO optimization. See the comments of `getIRPGOObjectName` for details. 3685f757f3fSDimitry Andric std::string getIRPGOFuncName(const Function &F, bool InLTO) { 3695f757f3fSDimitry Andric return getIRPGOObjectName(F, InLTO, getPGOFuncNameMetadata(F)); 3705f757f3fSDimitry Andric } 3715f757f3fSDimitry Andric 372cb14a3feSDimitry Andric // Please use getIRPGOFuncName for LLVM IR instrumentation. This function is 373cb14a3feSDimitry Andric // for front-end (Clang, etc) instrumentation. 374cb14a3feSDimitry Andric // The implementation is kept for profile matching from older profiles. 3755f757f3fSDimitry Andric // This is similar to `getIRPGOFuncName` except that this function calls 3765f757f3fSDimitry Andric // 'getPGOFuncName' to get a name and `getIRPGOFuncName` calls 3775f757f3fSDimitry Andric // 'getIRPGONameForGlobalObject'. See the difference between two callees in the 3785f757f3fSDimitry Andric // comments of `getIRPGONameForGlobalObject`. 3790b57cec5SDimitry Andric std::string getPGOFuncName(const Function &F, bool InLTO, uint64_t Version) { 3800b57cec5SDimitry Andric if (!InLTO) { 3815f757f3fSDimitry Andric auto FileName = getStrippedSourceFileName(F); 3820b57cec5SDimitry Andric return getPGOFuncName(F.getName(), F.getLinkage(), FileName, Version); 3830b57cec5SDimitry Andric } 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric // In LTO mode (when InLTO is true), first check if there is a meta data. 3865f757f3fSDimitry Andric if (auto PGOFuncName = lookupPGONameFromMetadata(getPGOFuncNameMetadata(F))) 3875f757f3fSDimitry Andric return *PGOFuncName; 3880b57cec5SDimitry Andric 3890b57cec5SDimitry Andric // If there is no meta data, the function must be a global before the value 3900b57cec5SDimitry Andric // profile annotation pass. Its current linkage may be internal if it is 3910b57cec5SDimitry Andric // internalized in LTO mode. 3920b57cec5SDimitry Andric return getPGOFuncName(F.getName(), GlobalValue::ExternalLinkage, ""); 3930b57cec5SDimitry Andric } 3940b57cec5SDimitry Andric 395*0fca6ea1SDimitry Andric std::string getPGOName(const GlobalVariable &V, bool InLTO) { 396*0fca6ea1SDimitry Andric // PGONameMetadata should be set by compiler at profile use time 397*0fca6ea1SDimitry Andric // and read by symtab creation to look up symbols corresponding to 398*0fca6ea1SDimitry Andric // a MD5 hash. 399*0fca6ea1SDimitry Andric return getIRPGOObjectName(V, InLTO, V.getMetadata(getPGONameMetadataName())); 400*0fca6ea1SDimitry Andric } 401*0fca6ea1SDimitry Andric 402*0fca6ea1SDimitry Andric // See getIRPGOObjectName() for a discription of the format. 403*0fca6ea1SDimitry Andric std::pair<StringRef, StringRef> getParsedIRPGOName(StringRef IRPGOName) { 404*0fca6ea1SDimitry Andric auto [FileName, MangledName] = IRPGOName.split(GlobalIdentifierDelimiter); 405*0fca6ea1SDimitry Andric if (MangledName.empty()) 406*0fca6ea1SDimitry Andric return std::make_pair(StringRef(), IRPGOName); 407*0fca6ea1SDimitry Andric return std::make_pair(FileName, MangledName); 4085f757f3fSDimitry Andric } 4095f757f3fSDimitry Andric 4100b57cec5SDimitry Andric StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName, StringRef FileName) { 4110b57cec5SDimitry Andric if (FileName.empty()) 4120b57cec5SDimitry Andric return PGOFuncName; 413cb14a3feSDimitry Andric // Drop the file name including ':' or ';'. See getIRPGONameForGlobalObject as 414cb14a3feSDimitry Andric // well. 4155f757f3fSDimitry Andric if (PGOFuncName.starts_with(FileName)) 4160b57cec5SDimitry Andric PGOFuncName = PGOFuncName.drop_front(FileName.size() + 1); 4170b57cec5SDimitry Andric return PGOFuncName; 4180b57cec5SDimitry Andric } 4190b57cec5SDimitry Andric 4200b57cec5SDimitry Andric // \p FuncName is the string used as profile lookup key for the function. A 4210b57cec5SDimitry Andric // symbol is created to hold the name. Return the legalized symbol name. 4220b57cec5SDimitry Andric std::string getPGOFuncNameVarName(StringRef FuncName, 4230b57cec5SDimitry Andric GlobalValue::LinkageTypes Linkage) { 4245ffd83dbSDimitry Andric std::string VarName = std::string(getInstrProfNameVarPrefix()); 4250b57cec5SDimitry Andric VarName += FuncName; 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric if (!GlobalValue::isLocalLinkage(Linkage)) 4280b57cec5SDimitry Andric return VarName; 4290b57cec5SDimitry Andric 4300b57cec5SDimitry Andric // Now fix up illegal chars in local VarName that may upset the assembler. 4315f757f3fSDimitry Andric const char InvalidChars[] = "-:;<>/\"'"; 432*0fca6ea1SDimitry Andric size_t FoundPos = VarName.find_first_of(InvalidChars); 433*0fca6ea1SDimitry Andric while (FoundPos != std::string::npos) { 434*0fca6ea1SDimitry Andric VarName[FoundPos] = '_'; 435*0fca6ea1SDimitry Andric FoundPos = VarName.find_first_of(InvalidChars, FoundPos + 1); 4360b57cec5SDimitry Andric } 4370b57cec5SDimitry Andric return VarName; 4380b57cec5SDimitry Andric } 4390b57cec5SDimitry Andric 4400b57cec5SDimitry Andric GlobalVariable *createPGOFuncNameVar(Module &M, 4410b57cec5SDimitry Andric GlobalValue::LinkageTypes Linkage, 4420b57cec5SDimitry Andric StringRef PGOFuncName) { 4430b57cec5SDimitry Andric // We generally want to match the function's linkage, but available_externally 4440b57cec5SDimitry Andric // and extern_weak both have the wrong semantics, and anything that doesn't 4450b57cec5SDimitry Andric // need to link across compilation units doesn't need to be visible at all. 4460b57cec5SDimitry Andric if (Linkage == GlobalValue::ExternalWeakLinkage) 4470b57cec5SDimitry Andric Linkage = GlobalValue::LinkOnceAnyLinkage; 4480b57cec5SDimitry Andric else if (Linkage == GlobalValue::AvailableExternallyLinkage) 4490b57cec5SDimitry Andric Linkage = GlobalValue::LinkOnceODRLinkage; 4500b57cec5SDimitry Andric else if (Linkage == GlobalValue::InternalLinkage || 4510b57cec5SDimitry Andric Linkage == GlobalValue::ExternalLinkage) 4520b57cec5SDimitry Andric Linkage = GlobalValue::PrivateLinkage; 4530b57cec5SDimitry Andric 4540b57cec5SDimitry Andric auto *Value = 4550b57cec5SDimitry Andric ConstantDataArray::getString(M.getContext(), PGOFuncName, false); 456*0fca6ea1SDimitry Andric auto *FuncNameVar = 4570b57cec5SDimitry Andric new GlobalVariable(M, Value->getType(), true, Linkage, Value, 4580b57cec5SDimitry Andric getPGOFuncNameVarName(PGOFuncName, Linkage)); 4590b57cec5SDimitry Andric 4600b57cec5SDimitry Andric // Hide the symbol so that we correctly get a copy for each executable. 4610b57cec5SDimitry Andric if (!GlobalValue::isLocalLinkage(FuncNameVar->getLinkage())) 4620b57cec5SDimitry Andric FuncNameVar->setVisibility(GlobalValue::HiddenVisibility); 4630b57cec5SDimitry Andric 4640b57cec5SDimitry Andric return FuncNameVar; 4650b57cec5SDimitry Andric } 4660b57cec5SDimitry Andric 4670b57cec5SDimitry Andric GlobalVariable *createPGOFuncNameVar(Function &F, StringRef PGOFuncName) { 4680b57cec5SDimitry Andric return createPGOFuncNameVar(*F.getParent(), F.getLinkage(), PGOFuncName); 4690b57cec5SDimitry Andric } 4700b57cec5SDimitry Andric 4710b57cec5SDimitry Andric Error InstrProfSymtab::create(Module &M, bool InLTO) { 4720b57cec5SDimitry Andric for (Function &F : M) { 4730b57cec5SDimitry Andric // Function may not have a name: like using asm("") to overwrite the name. 4740b57cec5SDimitry Andric // Ignore in this case. 4750b57cec5SDimitry Andric if (!F.hasName()) 4760b57cec5SDimitry Andric continue; 4775f757f3fSDimitry Andric if (Error E = addFuncWithName(F, getIRPGOFuncName(F, InLTO))) 4785f757f3fSDimitry Andric return E; 4795f757f3fSDimitry Andric // Also use getPGOFuncName() so that we can find records from older profiles 4805f757f3fSDimitry Andric if (Error E = addFuncWithName(F, getPGOFuncName(F, InLTO))) 4815f757f3fSDimitry Andric return E; 4825f757f3fSDimitry Andric } 483*0fca6ea1SDimitry Andric 484*0fca6ea1SDimitry Andric SmallVector<MDNode *, 2> Types; 485*0fca6ea1SDimitry Andric for (GlobalVariable &G : M.globals()) { 486*0fca6ea1SDimitry Andric if (!G.hasName() || !G.hasMetadata(LLVMContext::MD_type)) 487*0fca6ea1SDimitry Andric continue; 488*0fca6ea1SDimitry Andric if (Error E = addVTableWithName(G, getPGOName(G, InLTO))) 489*0fca6ea1SDimitry Andric return E; 490*0fca6ea1SDimitry Andric } 491*0fca6ea1SDimitry Andric 4925f757f3fSDimitry Andric Sorted = false; 4935f757f3fSDimitry Andric finalizeSymtab(); 4945f757f3fSDimitry Andric return Error::success(); 4955f757f3fSDimitry Andric } 4965f757f3fSDimitry Andric 497*0fca6ea1SDimitry Andric Error InstrProfSymtab::addVTableWithName(GlobalVariable &VTable, 498*0fca6ea1SDimitry Andric StringRef VTablePGOName) { 499*0fca6ea1SDimitry Andric auto NameToGUIDMap = [&](StringRef Name) -> Error { 500*0fca6ea1SDimitry Andric if (Error E = addSymbolName(Name)) 501*0fca6ea1SDimitry Andric return E; 502*0fca6ea1SDimitry Andric 503*0fca6ea1SDimitry Andric bool Inserted = true; 504*0fca6ea1SDimitry Andric std::tie(std::ignore, Inserted) = 505*0fca6ea1SDimitry Andric MD5VTableMap.try_emplace(GlobalValue::getGUID(Name), &VTable); 506*0fca6ea1SDimitry Andric if (!Inserted) 507*0fca6ea1SDimitry Andric LLVM_DEBUG(dbgs() << "GUID conflict within one module"); 508*0fca6ea1SDimitry Andric return Error::success(); 509*0fca6ea1SDimitry Andric }; 510*0fca6ea1SDimitry Andric if (Error E = NameToGUIDMap(VTablePGOName)) 511*0fca6ea1SDimitry Andric return E; 512*0fca6ea1SDimitry Andric 513*0fca6ea1SDimitry Andric StringRef CanonicalName = getCanonicalName(VTablePGOName); 514*0fca6ea1SDimitry Andric if (CanonicalName != VTablePGOName) 515*0fca6ea1SDimitry Andric return NameToGUIDMap(CanonicalName); 516*0fca6ea1SDimitry Andric 517*0fca6ea1SDimitry Andric return Error::success(); 518*0fca6ea1SDimitry Andric } 519*0fca6ea1SDimitry Andric 5205f757f3fSDimitry Andric /// \c NameStrings is a string composed of one of more possibly encoded 5215f757f3fSDimitry Andric /// sub-strings. The substrings are separated by 0 or more zero bytes. This 5225f757f3fSDimitry Andric /// method decodes the string and calls `NameCallback` for each substring. 5235f757f3fSDimitry Andric static Error 5245f757f3fSDimitry Andric readAndDecodeStrings(StringRef NameStrings, 5255f757f3fSDimitry Andric std::function<Error(StringRef)> NameCallback) { 5265f757f3fSDimitry Andric const uint8_t *P = NameStrings.bytes_begin(); 5275f757f3fSDimitry Andric const uint8_t *EndP = NameStrings.bytes_end(); 5285f757f3fSDimitry Andric while (P < EndP) { 5295f757f3fSDimitry Andric uint32_t N; 5305f757f3fSDimitry Andric uint64_t UncompressedSize = decodeULEB128(P, &N); 5315f757f3fSDimitry Andric P += N; 5325f757f3fSDimitry Andric uint64_t CompressedSize = decodeULEB128(P, &N); 5335f757f3fSDimitry Andric P += N; 534*0fca6ea1SDimitry Andric const bool IsCompressed = (CompressedSize != 0); 5355f757f3fSDimitry Andric SmallVector<uint8_t, 128> UncompressedNameStrings; 5365f757f3fSDimitry Andric StringRef NameStrings; 537*0fca6ea1SDimitry Andric if (IsCompressed) { 5385f757f3fSDimitry Andric if (!llvm::compression::zlib::isAvailable()) 5395f757f3fSDimitry Andric return make_error<InstrProfError>(instrprof_error::zlib_unavailable); 5405f757f3fSDimitry Andric 5415f757f3fSDimitry Andric if (Error E = compression::zlib::decompress(ArrayRef(P, CompressedSize), 5425f757f3fSDimitry Andric UncompressedNameStrings, 5435f757f3fSDimitry Andric UncompressedSize)) { 5445f757f3fSDimitry Andric consumeError(std::move(E)); 5455f757f3fSDimitry Andric return make_error<InstrProfError>(instrprof_error::uncompress_failed); 5465f757f3fSDimitry Andric } 5475f757f3fSDimitry Andric P += CompressedSize; 5485f757f3fSDimitry Andric NameStrings = toStringRef(UncompressedNameStrings); 5495f757f3fSDimitry Andric } else { 5505f757f3fSDimitry Andric NameStrings = 5515f757f3fSDimitry Andric StringRef(reinterpret_cast<const char *>(P), UncompressedSize); 5525f757f3fSDimitry Andric P += UncompressedSize; 5535f757f3fSDimitry Andric } 5545f757f3fSDimitry Andric // Now parse the name strings. 5555f757f3fSDimitry Andric SmallVector<StringRef, 0> Names; 5565f757f3fSDimitry Andric NameStrings.split(Names, getInstrProfNameSeparator()); 5575f757f3fSDimitry Andric for (StringRef &Name : Names) 5585f757f3fSDimitry Andric if (Error E = NameCallback(Name)) 5595f757f3fSDimitry Andric return E; 5605f757f3fSDimitry Andric 5615f757f3fSDimitry Andric while (P < EndP && *P == 0) 5625f757f3fSDimitry Andric P++; 5635f757f3fSDimitry Andric } 5645f757f3fSDimitry Andric return Error::success(); 5655f757f3fSDimitry Andric } 5665f757f3fSDimitry Andric 5675f757f3fSDimitry Andric Error InstrProfSymtab::create(StringRef NameStrings) { 5685f757f3fSDimitry Andric return readAndDecodeStrings( 5695f757f3fSDimitry Andric NameStrings, 5705f757f3fSDimitry Andric std::bind(&InstrProfSymtab::addFuncName, this, std::placeholders::_1)); 5715f757f3fSDimitry Andric } 5725f757f3fSDimitry Andric 573*0fca6ea1SDimitry Andric Error InstrProfSymtab::create(StringRef FuncNameStrings, 574*0fca6ea1SDimitry Andric StringRef VTableNameStrings) { 575*0fca6ea1SDimitry Andric if (Error E = readAndDecodeStrings(FuncNameStrings, 576*0fca6ea1SDimitry Andric std::bind(&InstrProfSymtab::addFuncName, 577*0fca6ea1SDimitry Andric this, std::placeholders::_1))) 5780b57cec5SDimitry Andric return E; 579*0fca6ea1SDimitry Andric 580*0fca6ea1SDimitry Andric return readAndDecodeStrings( 581*0fca6ea1SDimitry Andric VTableNameStrings, 582*0fca6ea1SDimitry Andric std::bind(&InstrProfSymtab::addVTableName, this, std::placeholders::_1)); 583*0fca6ea1SDimitry Andric } 584*0fca6ea1SDimitry Andric 585*0fca6ea1SDimitry Andric Error InstrProfSymtab::initVTableNamesFromCompressedStrings( 586*0fca6ea1SDimitry Andric StringRef CompressedVTableStrings) { 587*0fca6ea1SDimitry Andric return readAndDecodeStrings( 588*0fca6ea1SDimitry Andric CompressedVTableStrings, 589*0fca6ea1SDimitry Andric std::bind(&InstrProfSymtab::addVTableName, this, std::placeholders::_1)); 590*0fca6ea1SDimitry Andric } 591*0fca6ea1SDimitry Andric 592*0fca6ea1SDimitry Andric StringRef InstrProfSymtab::getCanonicalName(StringRef PGOName) { 5930b57cec5SDimitry Andric // In ThinLTO, local function may have been promoted to global and have 594fe6060f1SDimitry Andric // suffix ".llvm." added to the function name. We need to add the 595fe6060f1SDimitry Andric // stripped function name to the symbol table so that we can find a match 596fe6060f1SDimitry Andric // from profile. 597fe6060f1SDimitry Andric // 598*0fca6ea1SDimitry Andric // ".__uniq." suffix is used to differentiate internal linkage functions in 599*0fca6ea1SDimitry Andric // different modules and should be kept. This is the only suffix with the 600*0fca6ea1SDimitry Andric // pattern ".xxx" which is kept before matching, other suffixes similar as 601*0fca6ea1SDimitry Andric // ".llvm." will be stripped. 602fe6060f1SDimitry Andric const std::string UniqSuffix = ".__uniq."; 603*0fca6ea1SDimitry Andric size_t Pos = PGOName.find(UniqSuffix); 604*0fca6ea1SDimitry Andric if (Pos != StringRef::npos) 605*0fca6ea1SDimitry Andric Pos += UniqSuffix.length(); 606fe6060f1SDimitry Andric else 607*0fca6ea1SDimitry Andric Pos = 0; 608*0fca6ea1SDimitry Andric 609*0fca6ea1SDimitry Andric // Search '.' after ".__uniq." if ".__uniq." exists, otherwise search '.' from 610*0fca6ea1SDimitry Andric // the beginning. 611*0fca6ea1SDimitry Andric Pos = PGOName.find('.', Pos); 612*0fca6ea1SDimitry Andric if (Pos != StringRef::npos && Pos != 0) 613*0fca6ea1SDimitry Andric return PGOName.substr(0, Pos); 614*0fca6ea1SDimitry Andric 615*0fca6ea1SDimitry Andric return PGOName; 6160b57cec5SDimitry Andric } 617*0fca6ea1SDimitry Andric 618*0fca6ea1SDimitry Andric Error InstrProfSymtab::addFuncWithName(Function &F, StringRef PGOFuncName) { 619*0fca6ea1SDimitry Andric auto NameToGUIDMap = [&](StringRef Name) -> Error { 620*0fca6ea1SDimitry Andric if (Error E = addFuncName(Name)) 621*0fca6ea1SDimitry Andric return E; 622*0fca6ea1SDimitry Andric MD5FuncMap.emplace_back(Function::getGUID(Name), &F); 6230b57cec5SDimitry Andric return Error::success(); 624*0fca6ea1SDimitry Andric }; 625*0fca6ea1SDimitry Andric if (Error E = NameToGUIDMap(PGOFuncName)) 626*0fca6ea1SDimitry Andric return E; 627*0fca6ea1SDimitry Andric 628*0fca6ea1SDimitry Andric StringRef CanonicalFuncName = getCanonicalName(PGOFuncName); 629*0fca6ea1SDimitry Andric if (CanonicalFuncName != PGOFuncName) 630*0fca6ea1SDimitry Andric return NameToGUIDMap(CanonicalFuncName); 631*0fca6ea1SDimitry Andric 632*0fca6ea1SDimitry Andric return Error::success(); 633*0fca6ea1SDimitry Andric } 634*0fca6ea1SDimitry Andric 635*0fca6ea1SDimitry Andric uint64_t InstrProfSymtab::getVTableHashFromAddress(uint64_t Address) { 636*0fca6ea1SDimitry Andric // Given a runtime address, look up the hash value in the interval map, and 637*0fca6ea1SDimitry Andric // fallback to value 0 if a hash value is not found. 638*0fca6ea1SDimitry Andric return VTableAddrMap.lookup(Address, 0); 6390b57cec5SDimitry Andric } 6400b57cec5SDimitry Andric 6410b57cec5SDimitry Andric uint64_t InstrProfSymtab::getFunctionHashFromAddress(uint64_t Address) { 6420b57cec5SDimitry Andric finalizeSymtab(); 6430b57cec5SDimitry Andric auto It = partition_point(AddrToMD5Map, [=](std::pair<uint64_t, uint64_t> A) { 6440b57cec5SDimitry Andric return A.first < Address; 6450b57cec5SDimitry Andric }); 6460b57cec5SDimitry Andric // Raw function pointer collected by value profiler may be from 6470b57cec5SDimitry Andric // external functions that are not instrumented. They won't have 6480b57cec5SDimitry Andric // mapping data to be used by the deserializer. Force the value to 6490b57cec5SDimitry Andric // be 0 in this case. 6500b57cec5SDimitry Andric if (It != AddrToMD5Map.end() && It->first == Address) 6510b57cec5SDimitry Andric return (uint64_t)It->second; 6520b57cec5SDimitry Andric return 0; 6530b57cec5SDimitry Andric } 6540b57cec5SDimitry Andric 65506c3fb27SDimitry Andric void InstrProfSymtab::dumpNames(raw_ostream &OS) const { 65606c3fb27SDimitry Andric SmallVector<StringRef, 0> Sorted(NameTab.keys()); 65706c3fb27SDimitry Andric llvm::sort(Sorted); 65806c3fb27SDimitry Andric for (StringRef S : Sorted) 65906c3fb27SDimitry Andric OS << S << '\n'; 66006c3fb27SDimitry Andric } 66106c3fb27SDimitry Andric 6625f757f3fSDimitry Andric Error collectGlobalObjectNameStrings(ArrayRef<std::string> NameStrs, 663*0fca6ea1SDimitry Andric bool DoCompression, std::string &Result) { 6640b57cec5SDimitry Andric assert(!NameStrs.empty() && "No name data to emit"); 6650b57cec5SDimitry Andric 6665f757f3fSDimitry Andric uint8_t Header[20], *P = Header; 6670b57cec5SDimitry Andric std::string UncompressedNameStrings = 6680b57cec5SDimitry Andric join(NameStrs.begin(), NameStrs.end(), getInstrProfNameSeparator()); 6690b57cec5SDimitry Andric 6700b57cec5SDimitry Andric assert(StringRef(UncompressedNameStrings) 6710b57cec5SDimitry Andric .count(getInstrProfNameSeparator()) == (NameStrs.size() - 1) && 6720b57cec5SDimitry Andric "PGO name is invalid (contains separator token)"); 6730b57cec5SDimitry Andric 6740b57cec5SDimitry Andric unsigned EncLen = encodeULEB128(UncompressedNameStrings.length(), P); 6750b57cec5SDimitry Andric P += EncLen; 6760b57cec5SDimitry Andric 6770b57cec5SDimitry Andric auto WriteStringToResult = [&](size_t CompressedLen, StringRef InputStr) { 6780b57cec5SDimitry Andric EncLen = encodeULEB128(CompressedLen, P); 6790b57cec5SDimitry Andric P += EncLen; 6800b57cec5SDimitry Andric char *HeaderStr = reinterpret_cast<char *>(&Header[0]); 6810b57cec5SDimitry Andric unsigned HeaderLen = P - &Header[0]; 6820b57cec5SDimitry Andric Result.append(HeaderStr, HeaderLen); 6830b57cec5SDimitry Andric Result += InputStr; 6840b57cec5SDimitry Andric return Error::success(); 6850b57cec5SDimitry Andric }; 6860b57cec5SDimitry Andric 687*0fca6ea1SDimitry Andric if (!DoCompression) { 6880b57cec5SDimitry Andric return WriteStringToResult(0, UncompressedNameStrings); 6890b57cec5SDimitry Andric } 6900b57cec5SDimitry Andric 691753f127fSDimitry Andric SmallVector<uint8_t, 128> CompressedNameStrings; 692753f127fSDimitry Andric compression::zlib::compress(arrayRefFromStringRef(UncompressedNameStrings), 693753f127fSDimitry Andric CompressedNameStrings, 694753f127fSDimitry Andric compression::zlib::BestSizeCompression); 6950b57cec5SDimitry Andric 6960b57cec5SDimitry Andric return WriteStringToResult(CompressedNameStrings.size(), 697753f127fSDimitry Andric toStringRef(CompressedNameStrings)); 6980b57cec5SDimitry Andric } 6990b57cec5SDimitry Andric 7000b57cec5SDimitry Andric StringRef getPGOFuncNameVarInitializer(GlobalVariable *NameVar) { 7010b57cec5SDimitry Andric auto *Arr = cast<ConstantDataArray>(NameVar->getInitializer()); 7020b57cec5SDimitry Andric StringRef NameStr = 7030b57cec5SDimitry Andric Arr->isCString() ? Arr->getAsCString() : Arr->getAsString(); 7040b57cec5SDimitry Andric return NameStr; 7050b57cec5SDimitry Andric } 7060b57cec5SDimitry Andric 7070b57cec5SDimitry Andric Error collectPGOFuncNameStrings(ArrayRef<GlobalVariable *> NameVars, 708*0fca6ea1SDimitry Andric std::string &Result, bool DoCompression) { 7090b57cec5SDimitry Andric std::vector<std::string> NameStrs; 7100b57cec5SDimitry Andric for (auto *NameVar : NameVars) { 7115ffd83dbSDimitry Andric NameStrs.push_back(std::string(getPGOFuncNameVarInitializer(NameVar))); 7120b57cec5SDimitry Andric } 7135f757f3fSDimitry Andric return collectGlobalObjectNameStrings( 714*0fca6ea1SDimitry Andric NameStrs, compression::zlib::isAvailable() && DoCompression, Result); 715*0fca6ea1SDimitry Andric } 716*0fca6ea1SDimitry Andric 717*0fca6ea1SDimitry Andric Error collectVTableStrings(ArrayRef<GlobalVariable *> VTables, 718*0fca6ea1SDimitry Andric std::string &Result, bool DoCompression) { 719*0fca6ea1SDimitry Andric std::vector<std::string> VTableNameStrs; 720*0fca6ea1SDimitry Andric for (auto *VTable : VTables) 721*0fca6ea1SDimitry Andric VTableNameStrs.push_back(getPGOName(*VTable)); 722*0fca6ea1SDimitry Andric return collectGlobalObjectNameStrings( 723*0fca6ea1SDimitry Andric VTableNameStrs, compression::zlib::isAvailable() && DoCompression, 724*0fca6ea1SDimitry Andric Result); 7250b57cec5SDimitry Andric } 7260b57cec5SDimitry Andric 7278bcb0991SDimitry Andric void InstrProfRecord::accumulateCounts(CountSumOrPercent &Sum) const { 7280b57cec5SDimitry Andric uint64_t FuncSum = 0; 7290b57cec5SDimitry Andric Sum.NumEntries += Counts.size(); 7300eae32dcSDimitry Andric for (uint64_t Count : Counts) 7310eae32dcSDimitry Andric FuncSum += Count; 7320b57cec5SDimitry Andric Sum.CountSum += FuncSum; 7330b57cec5SDimitry Andric 7340b57cec5SDimitry Andric for (uint32_t VK = IPVK_First; VK <= IPVK_Last; ++VK) { 7350b57cec5SDimitry Andric uint64_t KindSum = 0; 7360b57cec5SDimitry Andric uint32_t NumValueSites = getNumValueSites(VK); 7370b57cec5SDimitry Andric for (size_t I = 0; I < NumValueSites; ++I) { 738*0fca6ea1SDimitry Andric for (const auto &V : getValueArrayForSite(VK, I)) 739*0fca6ea1SDimitry Andric KindSum += V.Count; 7400b57cec5SDimitry Andric } 7410b57cec5SDimitry Andric Sum.ValueCounts[VK] += KindSum; 7420b57cec5SDimitry Andric } 7430b57cec5SDimitry Andric } 7440b57cec5SDimitry Andric 7450b57cec5SDimitry Andric void InstrProfValueSiteRecord::overlap(InstrProfValueSiteRecord &Input, 7460b57cec5SDimitry Andric uint32_t ValueKind, 7470b57cec5SDimitry Andric OverlapStats &Overlap, 7480b57cec5SDimitry Andric OverlapStats &FuncLevelOverlap) { 7490b57cec5SDimitry Andric this->sortByTargetValues(); 7500b57cec5SDimitry Andric Input.sortByTargetValues(); 7510b57cec5SDimitry Andric double Score = 0.0f, FuncLevelScore = 0.0f; 7520b57cec5SDimitry Andric auto I = ValueData.begin(); 7530b57cec5SDimitry Andric auto IE = ValueData.end(); 7540b57cec5SDimitry Andric auto J = Input.ValueData.begin(); 7550b57cec5SDimitry Andric auto JE = Input.ValueData.end(); 7560b57cec5SDimitry Andric while (I != IE && J != JE) { 7570b57cec5SDimitry Andric if (I->Value == J->Value) { 7580b57cec5SDimitry Andric Score += OverlapStats::score(I->Count, J->Count, 7590b57cec5SDimitry Andric Overlap.Base.ValueCounts[ValueKind], 7600b57cec5SDimitry Andric Overlap.Test.ValueCounts[ValueKind]); 7610b57cec5SDimitry Andric FuncLevelScore += OverlapStats::score( 7620b57cec5SDimitry Andric I->Count, J->Count, FuncLevelOverlap.Base.ValueCounts[ValueKind], 7630b57cec5SDimitry Andric FuncLevelOverlap.Test.ValueCounts[ValueKind]); 7640b57cec5SDimitry Andric ++I; 7650b57cec5SDimitry Andric } else if (I->Value < J->Value) { 7660b57cec5SDimitry Andric ++I; 7670b57cec5SDimitry Andric continue; 7680b57cec5SDimitry Andric } 7690b57cec5SDimitry Andric ++J; 7700b57cec5SDimitry Andric } 7710b57cec5SDimitry Andric Overlap.Overlap.ValueCounts[ValueKind] += Score; 7720b57cec5SDimitry Andric FuncLevelOverlap.Overlap.ValueCounts[ValueKind] += FuncLevelScore; 7730b57cec5SDimitry Andric } 7740b57cec5SDimitry Andric 7750b57cec5SDimitry Andric // Return false on mismatch. 7760b57cec5SDimitry Andric void InstrProfRecord::overlapValueProfData(uint32_t ValueKind, 7770b57cec5SDimitry Andric InstrProfRecord &Other, 7780b57cec5SDimitry Andric OverlapStats &Overlap, 7790b57cec5SDimitry Andric OverlapStats &FuncLevelOverlap) { 7800b57cec5SDimitry Andric uint32_t ThisNumValueSites = getNumValueSites(ValueKind); 7810b57cec5SDimitry Andric assert(ThisNumValueSites == Other.getNumValueSites(ValueKind)); 7820b57cec5SDimitry Andric if (!ThisNumValueSites) 7830b57cec5SDimitry Andric return; 7840b57cec5SDimitry Andric 7850b57cec5SDimitry Andric std::vector<InstrProfValueSiteRecord> &ThisSiteRecords = 7860b57cec5SDimitry Andric getOrCreateValueSitesForKind(ValueKind); 7870b57cec5SDimitry Andric MutableArrayRef<InstrProfValueSiteRecord> OtherSiteRecords = 7880b57cec5SDimitry Andric Other.getValueSitesForKind(ValueKind); 7890b57cec5SDimitry Andric for (uint32_t I = 0; I < ThisNumValueSites; I++) 7900b57cec5SDimitry Andric ThisSiteRecords[I].overlap(OtherSiteRecords[I], ValueKind, Overlap, 7910b57cec5SDimitry Andric FuncLevelOverlap); 7920b57cec5SDimitry Andric } 7930b57cec5SDimitry Andric 7940b57cec5SDimitry Andric void InstrProfRecord::overlap(InstrProfRecord &Other, OverlapStats &Overlap, 7950b57cec5SDimitry Andric OverlapStats &FuncLevelOverlap, 7960b57cec5SDimitry Andric uint64_t ValueCutoff) { 7970b57cec5SDimitry Andric // FuncLevel CountSum for other should already computed and nonzero. 7980b57cec5SDimitry Andric assert(FuncLevelOverlap.Test.CountSum >= 1.0f); 7998bcb0991SDimitry Andric accumulateCounts(FuncLevelOverlap.Base); 8000b57cec5SDimitry Andric bool Mismatch = (Counts.size() != Other.Counts.size()); 8010b57cec5SDimitry Andric 8020b57cec5SDimitry Andric // Check if the value profiles mismatch. 8030b57cec5SDimitry Andric if (!Mismatch) { 8040b57cec5SDimitry Andric for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) { 8050b57cec5SDimitry Andric uint32_t ThisNumValueSites = getNumValueSites(Kind); 8060b57cec5SDimitry Andric uint32_t OtherNumValueSites = Other.getNumValueSites(Kind); 8070b57cec5SDimitry Andric if (ThisNumValueSites != OtherNumValueSites) { 8080b57cec5SDimitry Andric Mismatch = true; 8090b57cec5SDimitry Andric break; 8100b57cec5SDimitry Andric } 8110b57cec5SDimitry Andric } 8120b57cec5SDimitry Andric } 8130b57cec5SDimitry Andric if (Mismatch) { 8140b57cec5SDimitry Andric Overlap.addOneMismatch(FuncLevelOverlap.Test); 8150b57cec5SDimitry Andric return; 8160b57cec5SDimitry Andric } 8170b57cec5SDimitry Andric 8180b57cec5SDimitry Andric // Compute overlap for value counts. 8190b57cec5SDimitry Andric for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) 8200b57cec5SDimitry Andric overlapValueProfData(Kind, Other, Overlap, FuncLevelOverlap); 8210b57cec5SDimitry Andric 8220b57cec5SDimitry Andric double Score = 0.0; 8230b57cec5SDimitry Andric uint64_t MaxCount = 0; 8240b57cec5SDimitry Andric // Compute overlap for edge counts. 8250b57cec5SDimitry Andric for (size_t I = 0, E = Other.Counts.size(); I < E; ++I) { 8260b57cec5SDimitry Andric Score += OverlapStats::score(Counts[I], Other.Counts[I], 8270b57cec5SDimitry Andric Overlap.Base.CountSum, Overlap.Test.CountSum); 8280b57cec5SDimitry Andric MaxCount = std::max(Other.Counts[I], MaxCount); 8290b57cec5SDimitry Andric } 8300b57cec5SDimitry Andric Overlap.Overlap.CountSum += Score; 8310b57cec5SDimitry Andric Overlap.Overlap.NumEntries += 1; 8320b57cec5SDimitry Andric 8330b57cec5SDimitry Andric if (MaxCount >= ValueCutoff) { 8340b57cec5SDimitry Andric double FuncScore = 0.0; 8350b57cec5SDimitry Andric for (size_t I = 0, E = Other.Counts.size(); I < E; ++I) 8360b57cec5SDimitry Andric FuncScore += OverlapStats::score(Counts[I], Other.Counts[I], 8370b57cec5SDimitry Andric FuncLevelOverlap.Base.CountSum, 8380b57cec5SDimitry Andric FuncLevelOverlap.Test.CountSum); 8390b57cec5SDimitry Andric FuncLevelOverlap.Overlap.CountSum = FuncScore; 8400b57cec5SDimitry Andric FuncLevelOverlap.Overlap.NumEntries = Other.Counts.size(); 8410b57cec5SDimitry Andric FuncLevelOverlap.Valid = true; 8420b57cec5SDimitry Andric } 8430b57cec5SDimitry Andric } 8440b57cec5SDimitry Andric 8450b57cec5SDimitry Andric void InstrProfValueSiteRecord::merge(InstrProfValueSiteRecord &Input, 8460b57cec5SDimitry Andric uint64_t Weight, 8470b57cec5SDimitry Andric function_ref<void(instrprof_error)> Warn) { 8480b57cec5SDimitry Andric this->sortByTargetValues(); 8490b57cec5SDimitry Andric Input.sortByTargetValues(); 8500b57cec5SDimitry Andric auto I = ValueData.begin(); 8510b57cec5SDimitry Andric auto IE = ValueData.end(); 852*0fca6ea1SDimitry Andric std::vector<InstrProfValueData> Merged; 853*0fca6ea1SDimitry Andric Merged.reserve(std::max(ValueData.size(), Input.ValueData.size())); 8544824e7fdSDimitry Andric for (const InstrProfValueData &J : Input.ValueData) { 855*0fca6ea1SDimitry Andric while (I != IE && I->Value < J.Value) { 856*0fca6ea1SDimitry Andric Merged.push_back(*I); 8570b57cec5SDimitry Andric ++I; 858*0fca6ea1SDimitry Andric } 8594824e7fdSDimitry Andric if (I != IE && I->Value == J.Value) { 8600b57cec5SDimitry Andric bool Overflowed; 8614824e7fdSDimitry Andric I->Count = SaturatingMultiplyAdd(J.Count, Weight, I->Count, &Overflowed); 8620b57cec5SDimitry Andric if (Overflowed) 8630b57cec5SDimitry Andric Warn(instrprof_error::counter_overflow); 864*0fca6ea1SDimitry Andric Merged.push_back(*I); 8650b57cec5SDimitry Andric ++I; 8660b57cec5SDimitry Andric continue; 8670b57cec5SDimitry Andric } 868*0fca6ea1SDimitry Andric Merged.push_back(J); 8690b57cec5SDimitry Andric } 870*0fca6ea1SDimitry Andric Merged.insert(Merged.end(), I, IE); 871*0fca6ea1SDimitry Andric ValueData = std::move(Merged); 8720b57cec5SDimitry Andric } 8730b57cec5SDimitry Andric 874e8d8bef9SDimitry Andric void InstrProfValueSiteRecord::scale(uint64_t N, uint64_t D, 8750b57cec5SDimitry Andric function_ref<void(instrprof_error)> Warn) { 8760eae32dcSDimitry Andric for (InstrProfValueData &I : ValueData) { 8770b57cec5SDimitry Andric bool Overflowed; 8780eae32dcSDimitry Andric I.Count = SaturatingMultiply(I.Count, N, &Overflowed) / D; 8790b57cec5SDimitry Andric if (Overflowed) 8800b57cec5SDimitry Andric Warn(instrprof_error::counter_overflow); 8810b57cec5SDimitry Andric } 8820b57cec5SDimitry Andric } 8830b57cec5SDimitry Andric 8840b57cec5SDimitry Andric // Merge Value Profile data from Src record to this record for ValueKind. 8850b57cec5SDimitry Andric // Scale merged value counts by \p Weight. 8860b57cec5SDimitry Andric void InstrProfRecord::mergeValueProfData( 8870b57cec5SDimitry Andric uint32_t ValueKind, InstrProfRecord &Src, uint64_t Weight, 8880b57cec5SDimitry Andric function_ref<void(instrprof_error)> Warn) { 8890b57cec5SDimitry Andric uint32_t ThisNumValueSites = getNumValueSites(ValueKind); 8900b57cec5SDimitry Andric uint32_t OtherNumValueSites = Src.getNumValueSites(ValueKind); 8910b57cec5SDimitry Andric if (ThisNumValueSites != OtherNumValueSites) { 8920b57cec5SDimitry Andric Warn(instrprof_error::value_site_count_mismatch); 8930b57cec5SDimitry Andric return; 8940b57cec5SDimitry Andric } 8950b57cec5SDimitry Andric if (!ThisNumValueSites) 8960b57cec5SDimitry Andric return; 8970b57cec5SDimitry Andric std::vector<InstrProfValueSiteRecord> &ThisSiteRecords = 8980b57cec5SDimitry Andric getOrCreateValueSitesForKind(ValueKind); 8990b57cec5SDimitry Andric MutableArrayRef<InstrProfValueSiteRecord> OtherSiteRecords = 9000b57cec5SDimitry Andric Src.getValueSitesForKind(ValueKind); 9010b57cec5SDimitry Andric for (uint32_t I = 0; I < ThisNumValueSites; I++) 9020b57cec5SDimitry Andric ThisSiteRecords[I].merge(OtherSiteRecords[I], Weight, Warn); 9030b57cec5SDimitry Andric } 9040b57cec5SDimitry Andric 9050b57cec5SDimitry Andric void InstrProfRecord::merge(InstrProfRecord &Other, uint64_t Weight, 9060b57cec5SDimitry Andric function_ref<void(instrprof_error)> Warn) { 9070b57cec5SDimitry Andric // If the number of counters doesn't match we either have bad data 9080b57cec5SDimitry Andric // or a hash collision. 9090b57cec5SDimitry Andric if (Counts.size() != Other.Counts.size()) { 9100b57cec5SDimitry Andric Warn(instrprof_error::count_mismatch); 9110b57cec5SDimitry Andric return; 9120b57cec5SDimitry Andric } 9130b57cec5SDimitry Andric 914bdd1243dSDimitry Andric // Special handling of the first count as the PseudoCount. 915bdd1243dSDimitry Andric CountPseudoKind OtherKind = Other.getCountPseudoKind(); 916bdd1243dSDimitry Andric CountPseudoKind ThisKind = getCountPseudoKind(); 917bdd1243dSDimitry Andric if (OtherKind != NotPseudo || ThisKind != NotPseudo) { 918bdd1243dSDimitry Andric // We don't allow the merge of a profile with pseudo counts and 919bdd1243dSDimitry Andric // a normal profile (i.e. without pesudo counts). 920bdd1243dSDimitry Andric // Profile supplimenation should be done after the profile merge. 921bdd1243dSDimitry Andric if (OtherKind == NotPseudo || ThisKind == NotPseudo) { 922bdd1243dSDimitry Andric Warn(instrprof_error::count_mismatch); 923bdd1243dSDimitry Andric return; 924bdd1243dSDimitry Andric } 925bdd1243dSDimitry Andric if (OtherKind == PseudoHot || ThisKind == PseudoHot) 926bdd1243dSDimitry Andric setPseudoCount(PseudoHot); 927bdd1243dSDimitry Andric else 928bdd1243dSDimitry Andric setPseudoCount(PseudoWarm); 929bdd1243dSDimitry Andric return; 930bdd1243dSDimitry Andric } 931bdd1243dSDimitry Andric 9320b57cec5SDimitry Andric for (size_t I = 0, E = Other.Counts.size(); I < E; ++I) { 9330b57cec5SDimitry Andric bool Overflowed; 934bdd1243dSDimitry Andric uint64_t Value = 9350b57cec5SDimitry Andric SaturatingMultiplyAdd(Other.Counts[I], Weight, Counts[I], &Overflowed); 936bdd1243dSDimitry Andric if (Value > getInstrMaxCountValue()) { 937bdd1243dSDimitry Andric Value = getInstrMaxCountValue(); 938bdd1243dSDimitry Andric Overflowed = true; 939bdd1243dSDimitry Andric } 940bdd1243dSDimitry Andric Counts[I] = Value; 9410b57cec5SDimitry Andric if (Overflowed) 9420b57cec5SDimitry Andric Warn(instrprof_error::counter_overflow); 9430b57cec5SDimitry Andric } 9440b57cec5SDimitry Andric 9455f757f3fSDimitry Andric // If the number of bitmap bytes doesn't match we either have bad data 9465f757f3fSDimitry Andric // or a hash collision. 9475f757f3fSDimitry Andric if (BitmapBytes.size() != Other.BitmapBytes.size()) { 9485f757f3fSDimitry Andric Warn(instrprof_error::bitmap_mismatch); 9495f757f3fSDimitry Andric return; 9505f757f3fSDimitry Andric } 9515f757f3fSDimitry Andric 9525f757f3fSDimitry Andric // Bitmap bytes are merged by simply ORing them together. 9535f757f3fSDimitry Andric for (size_t I = 0, E = Other.BitmapBytes.size(); I < E; ++I) { 9545f757f3fSDimitry Andric BitmapBytes[I] = Other.BitmapBytes[I] | BitmapBytes[I]; 9555f757f3fSDimitry Andric } 9565f757f3fSDimitry Andric 9570b57cec5SDimitry Andric for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) 9580b57cec5SDimitry Andric mergeValueProfData(Kind, Other, Weight, Warn); 9590b57cec5SDimitry Andric } 9600b57cec5SDimitry Andric 9610b57cec5SDimitry Andric void InstrProfRecord::scaleValueProfData( 962e8d8bef9SDimitry Andric uint32_t ValueKind, uint64_t N, uint64_t D, 9630b57cec5SDimitry Andric function_ref<void(instrprof_error)> Warn) { 9640b57cec5SDimitry Andric for (auto &R : getValueSitesForKind(ValueKind)) 965e8d8bef9SDimitry Andric R.scale(N, D, Warn); 9660b57cec5SDimitry Andric } 9670b57cec5SDimitry Andric 968e8d8bef9SDimitry Andric void InstrProfRecord::scale(uint64_t N, uint64_t D, 9690b57cec5SDimitry Andric function_ref<void(instrprof_error)> Warn) { 970e8d8bef9SDimitry Andric assert(D != 0 && "D cannot be 0"); 9710b57cec5SDimitry Andric for (auto &Count : this->Counts) { 9720b57cec5SDimitry Andric bool Overflowed; 973e8d8bef9SDimitry Andric Count = SaturatingMultiply(Count, N, &Overflowed) / D; 974bdd1243dSDimitry Andric if (Count > getInstrMaxCountValue()) { 975bdd1243dSDimitry Andric Count = getInstrMaxCountValue(); 976bdd1243dSDimitry Andric Overflowed = true; 977bdd1243dSDimitry Andric } 9780b57cec5SDimitry Andric if (Overflowed) 9790b57cec5SDimitry Andric Warn(instrprof_error::counter_overflow); 9800b57cec5SDimitry Andric } 9810b57cec5SDimitry Andric for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) 982e8d8bef9SDimitry Andric scaleValueProfData(Kind, N, D, Warn); 9830b57cec5SDimitry Andric } 9840b57cec5SDimitry Andric 9850b57cec5SDimitry Andric // Map indirect call target name hash to name string. 9860b57cec5SDimitry Andric uint64_t InstrProfRecord::remapValue(uint64_t Value, uint32_t ValueKind, 9870b57cec5SDimitry Andric InstrProfSymtab *SymTab) { 9880b57cec5SDimitry Andric if (!SymTab) 9890b57cec5SDimitry Andric return Value; 9900b57cec5SDimitry Andric 9910b57cec5SDimitry Andric if (ValueKind == IPVK_IndirectCallTarget) 9920b57cec5SDimitry Andric return SymTab->getFunctionHashFromAddress(Value); 9930b57cec5SDimitry Andric 994*0fca6ea1SDimitry Andric if (ValueKind == IPVK_VTableTarget) 995*0fca6ea1SDimitry Andric return SymTab->getVTableHashFromAddress(Value); 996*0fca6ea1SDimitry Andric 9970b57cec5SDimitry Andric return Value; 9980b57cec5SDimitry Andric } 9990b57cec5SDimitry Andric 10000b57cec5SDimitry Andric void InstrProfRecord::addValueData(uint32_t ValueKind, uint32_t Site, 1001*0fca6ea1SDimitry Andric ArrayRef<InstrProfValueData> VData, 10020b57cec5SDimitry Andric InstrProfSymtab *ValueMap) { 1003*0fca6ea1SDimitry Andric // Remap values. 1004*0fca6ea1SDimitry Andric std::vector<InstrProfValueData> RemappedVD; 1005*0fca6ea1SDimitry Andric RemappedVD.reserve(VData.size()); 1006*0fca6ea1SDimitry Andric for (const auto &V : VData) { 1007*0fca6ea1SDimitry Andric uint64_t NewValue = remapValue(V.Value, ValueKind, ValueMap); 1008*0fca6ea1SDimitry Andric RemappedVD.push_back({NewValue, V.Count}); 10090b57cec5SDimitry Andric } 1010*0fca6ea1SDimitry Andric 10110b57cec5SDimitry Andric std::vector<InstrProfValueSiteRecord> &ValueSites = 10120b57cec5SDimitry Andric getOrCreateValueSitesForKind(ValueKind); 1013*0fca6ea1SDimitry Andric assert(ValueSites.size() == Site); 1014*0fca6ea1SDimitry Andric 1015*0fca6ea1SDimitry Andric // Add a new value site with remapped value profiling data. 1016*0fca6ea1SDimitry Andric ValueSites.emplace_back(std::move(RemappedVD)); 10170b57cec5SDimitry Andric } 10180b57cec5SDimitry Andric 1019*0fca6ea1SDimitry Andric void TemporalProfTraceTy::createBPFunctionNodes( 1020*0fca6ea1SDimitry Andric ArrayRef<TemporalProfTraceTy> Traces, std::vector<BPFunctionNode> &Nodes, 1021*0fca6ea1SDimitry Andric bool RemoveOutlierUNs) { 102206c3fb27SDimitry Andric using IDT = BPFunctionNode::IDT; 102306c3fb27SDimitry Andric using UtilityNodeT = BPFunctionNode::UtilityNodeT; 1024*0fca6ea1SDimitry Andric UtilityNodeT MaxUN = 0; 1025*0fca6ea1SDimitry Andric DenseMap<IDT, size_t> IdToFirstTimestamp; 1026*0fca6ea1SDimitry Andric DenseMap<IDT, UtilityNodeT> IdToFirstUN; 1027*0fca6ea1SDimitry Andric DenseMap<IDT, SmallVector<UtilityNodeT>> IdToUNs; 102806c3fb27SDimitry Andric // TODO: We need to use the Trace.Weight field to give more weight to more 102906c3fb27SDimitry Andric // important utilities 1030*0fca6ea1SDimitry Andric for (auto &Trace : Traces) { 1031*0fca6ea1SDimitry Andric size_t CutoffTimestamp = 1; 1032*0fca6ea1SDimitry Andric for (size_t Timestamp = 0; Timestamp < Trace.FunctionNameRefs.size(); 1033*0fca6ea1SDimitry Andric Timestamp++) { 1034*0fca6ea1SDimitry Andric IDT Id = Trace.FunctionNameRefs[Timestamp]; 1035*0fca6ea1SDimitry Andric auto [It, WasInserted] = IdToFirstTimestamp.try_emplace(Id, Timestamp); 1036*0fca6ea1SDimitry Andric if (!WasInserted) 1037*0fca6ea1SDimitry Andric It->getSecond() = std::min<size_t>(It->getSecond(), Timestamp); 1038*0fca6ea1SDimitry Andric if (Timestamp >= CutoffTimestamp) { 1039*0fca6ea1SDimitry Andric ++MaxUN; 1040*0fca6ea1SDimitry Andric CutoffTimestamp = 2 * Timestamp; 104106c3fb27SDimitry Andric } 1042*0fca6ea1SDimitry Andric IdToFirstUN.try_emplace(Id, MaxUN); 104306c3fb27SDimitry Andric } 1044*0fca6ea1SDimitry Andric for (auto &[Id, FirstUN] : IdToFirstUN) 1045*0fca6ea1SDimitry Andric for (auto UN = FirstUN; UN <= MaxUN; ++UN) 1046*0fca6ea1SDimitry Andric IdToUNs[Id].push_back(UN); 1047*0fca6ea1SDimitry Andric ++MaxUN; 1048*0fca6ea1SDimitry Andric IdToFirstUN.clear(); 104906c3fb27SDimitry Andric } 105006c3fb27SDimitry Andric 1051*0fca6ea1SDimitry Andric if (RemoveOutlierUNs) { 1052*0fca6ea1SDimitry Andric DenseMap<UtilityNodeT, unsigned> UNFrequency; 1053*0fca6ea1SDimitry Andric for (auto &[Id, UNs] : IdToUNs) 1054*0fca6ea1SDimitry Andric for (auto &UN : UNs) 1055*0fca6ea1SDimitry Andric ++UNFrequency[UN]; 1056*0fca6ea1SDimitry Andric // Filter out utility nodes that are too infrequent or too prevalent to make 1057*0fca6ea1SDimitry Andric // BalancedPartitioning more effective. 1058*0fca6ea1SDimitry Andric for (auto &[Id, UNs] : IdToUNs) 1059*0fca6ea1SDimitry Andric llvm::erase_if(UNs, [&](auto &UN) { 1060*0fca6ea1SDimitry Andric return UNFrequency[UN] <= 1 || 2 * UNFrequency[UN] > IdToUNs.size(); 1061*0fca6ea1SDimitry Andric }); 106206c3fb27SDimitry Andric } 1063*0fca6ea1SDimitry Andric 1064*0fca6ea1SDimitry Andric for (auto &[Id, UNs] : IdToUNs) 1065*0fca6ea1SDimitry Andric Nodes.emplace_back(Id, UNs); 1066*0fca6ea1SDimitry Andric 1067*0fca6ea1SDimitry Andric // Since BalancedPartitioning is sensitive to the initial order, we explicitly 1068*0fca6ea1SDimitry Andric // order nodes by their earliest timestamp. 1069*0fca6ea1SDimitry Andric llvm::sort(Nodes, [&](auto &L, auto &R) { 1070*0fca6ea1SDimitry Andric return std::make_pair(IdToFirstTimestamp[L.Id], L.Id) < 1071*0fca6ea1SDimitry Andric std::make_pair(IdToFirstTimestamp[R.Id], R.Id); 1072*0fca6ea1SDimitry Andric }); 107306c3fb27SDimitry Andric } 107406c3fb27SDimitry Andric 10750b57cec5SDimitry Andric #define INSTR_PROF_COMMON_API_IMPL 10760b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfData.inc" 10770b57cec5SDimitry Andric 10780b57cec5SDimitry Andric /*! 10790b57cec5SDimitry Andric * ValueProfRecordClosure Interface implementation for InstrProfRecord 10800b57cec5SDimitry Andric * class. These C wrappers are used as adaptors so that C++ code can be 10810b57cec5SDimitry Andric * invoked as callbacks. 10820b57cec5SDimitry Andric */ 10830b57cec5SDimitry Andric uint32_t getNumValueKindsInstrProf(const void *Record) { 10840b57cec5SDimitry Andric return reinterpret_cast<const InstrProfRecord *>(Record)->getNumValueKinds(); 10850b57cec5SDimitry Andric } 10860b57cec5SDimitry Andric 10870b57cec5SDimitry Andric uint32_t getNumValueSitesInstrProf(const void *Record, uint32_t VKind) { 10880b57cec5SDimitry Andric return reinterpret_cast<const InstrProfRecord *>(Record) 10890b57cec5SDimitry Andric ->getNumValueSites(VKind); 10900b57cec5SDimitry Andric } 10910b57cec5SDimitry Andric 10920b57cec5SDimitry Andric uint32_t getNumValueDataInstrProf(const void *Record, uint32_t VKind) { 10930b57cec5SDimitry Andric return reinterpret_cast<const InstrProfRecord *>(Record) 10940b57cec5SDimitry Andric ->getNumValueData(VKind); 10950b57cec5SDimitry Andric } 10960b57cec5SDimitry Andric 10970b57cec5SDimitry Andric uint32_t getNumValueDataForSiteInstrProf(const void *R, uint32_t VK, 10980b57cec5SDimitry Andric uint32_t S) { 1099*0fca6ea1SDimitry Andric const auto *IPR = reinterpret_cast<const InstrProfRecord *>(R); 1100*0fca6ea1SDimitry Andric return IPR->getValueArrayForSite(VK, S).size(); 11010b57cec5SDimitry Andric } 11020b57cec5SDimitry Andric 11030b57cec5SDimitry Andric void getValueForSiteInstrProf(const void *R, InstrProfValueData *Dst, 11040b57cec5SDimitry Andric uint32_t K, uint32_t S) { 1105*0fca6ea1SDimitry Andric const auto *IPR = reinterpret_cast<const InstrProfRecord *>(R); 1106*0fca6ea1SDimitry Andric llvm::copy(IPR->getValueArrayForSite(K, S), Dst); 11070b57cec5SDimitry Andric } 11080b57cec5SDimitry Andric 11090b57cec5SDimitry Andric ValueProfData *allocValueProfDataInstrProf(size_t TotalSizeInBytes) { 11100b57cec5SDimitry Andric ValueProfData *VD = 11110b57cec5SDimitry Andric (ValueProfData *)(new (::operator new(TotalSizeInBytes)) ValueProfData()); 11120b57cec5SDimitry Andric memset(VD, 0, TotalSizeInBytes); 11130b57cec5SDimitry Andric return VD; 11140b57cec5SDimitry Andric } 11150b57cec5SDimitry Andric 11160b57cec5SDimitry Andric static ValueProfRecordClosure InstrProfRecordClosure = { 11170b57cec5SDimitry Andric nullptr, 11180b57cec5SDimitry Andric getNumValueKindsInstrProf, 11190b57cec5SDimitry Andric getNumValueSitesInstrProf, 11200b57cec5SDimitry Andric getNumValueDataInstrProf, 11210b57cec5SDimitry Andric getNumValueDataForSiteInstrProf, 11220b57cec5SDimitry Andric nullptr, 11230b57cec5SDimitry Andric getValueForSiteInstrProf, 11240b57cec5SDimitry Andric allocValueProfDataInstrProf}; 11250b57cec5SDimitry Andric 11260b57cec5SDimitry Andric // Wrapper implementation using the closure mechanism. 11270b57cec5SDimitry Andric uint32_t ValueProfData::getSize(const InstrProfRecord &Record) { 11280b57cec5SDimitry Andric auto Closure = InstrProfRecordClosure; 11290b57cec5SDimitry Andric Closure.Record = &Record; 11300b57cec5SDimitry Andric return getValueProfDataSize(&Closure); 11310b57cec5SDimitry Andric } 11320b57cec5SDimitry Andric 11330b57cec5SDimitry Andric // Wrapper implementation using the closure mechanism. 11340b57cec5SDimitry Andric std::unique_ptr<ValueProfData> 11350b57cec5SDimitry Andric ValueProfData::serializeFrom(const InstrProfRecord &Record) { 11360b57cec5SDimitry Andric InstrProfRecordClosure.Record = &Record; 11370b57cec5SDimitry Andric 11380b57cec5SDimitry Andric std::unique_ptr<ValueProfData> VPD( 11390b57cec5SDimitry Andric serializeValueProfDataFrom(&InstrProfRecordClosure, nullptr)); 11400b57cec5SDimitry Andric return VPD; 11410b57cec5SDimitry Andric } 11420b57cec5SDimitry Andric 11430b57cec5SDimitry Andric void ValueProfRecord::deserializeTo(InstrProfRecord &Record, 11440b57cec5SDimitry Andric InstrProfSymtab *SymTab) { 11450b57cec5SDimitry Andric Record.reserveSites(Kind, NumValueSites); 11460b57cec5SDimitry Andric 11470b57cec5SDimitry Andric InstrProfValueData *ValueData = getValueProfRecordValueData(this); 11480b57cec5SDimitry Andric for (uint64_t VSite = 0; VSite < NumValueSites; ++VSite) { 11490b57cec5SDimitry Andric uint8_t ValueDataCount = this->SiteCountArray[VSite]; 1150*0fca6ea1SDimitry Andric ArrayRef<InstrProfValueData> VDs(ValueData, ValueDataCount); 1151*0fca6ea1SDimitry Andric Record.addValueData(Kind, VSite, VDs, SymTab); 11520b57cec5SDimitry Andric ValueData += ValueDataCount; 11530b57cec5SDimitry Andric } 11540b57cec5SDimitry Andric } 11550b57cec5SDimitry Andric 11560b57cec5SDimitry Andric // For writing/serializing, Old is the host endianness, and New is 11570b57cec5SDimitry Andric // byte order intended on disk. For Reading/deserialization, Old 11580b57cec5SDimitry Andric // is the on-disk source endianness, and New is the host endianness. 11595f757f3fSDimitry Andric void ValueProfRecord::swapBytes(llvm::endianness Old, llvm::endianness New) { 11600b57cec5SDimitry Andric using namespace support; 11610b57cec5SDimitry Andric 11620b57cec5SDimitry Andric if (Old == New) 11630b57cec5SDimitry Andric return; 11640b57cec5SDimitry Andric 11655f757f3fSDimitry Andric if (llvm::endianness::native != Old) { 11660b57cec5SDimitry Andric sys::swapByteOrder<uint32_t>(NumValueSites); 11670b57cec5SDimitry Andric sys::swapByteOrder<uint32_t>(Kind); 11680b57cec5SDimitry Andric } 11690b57cec5SDimitry Andric uint32_t ND = getValueProfRecordNumValueData(this); 11700b57cec5SDimitry Andric InstrProfValueData *VD = getValueProfRecordValueData(this); 11710b57cec5SDimitry Andric 11720b57cec5SDimitry Andric // No need to swap byte array: SiteCountArrray. 11730b57cec5SDimitry Andric for (uint32_t I = 0; I < ND; I++) { 11740b57cec5SDimitry Andric sys::swapByteOrder<uint64_t>(VD[I].Value); 11750b57cec5SDimitry Andric sys::swapByteOrder<uint64_t>(VD[I].Count); 11760b57cec5SDimitry Andric } 11775f757f3fSDimitry Andric if (llvm::endianness::native == Old) { 11780b57cec5SDimitry Andric sys::swapByteOrder<uint32_t>(NumValueSites); 11790b57cec5SDimitry Andric sys::swapByteOrder<uint32_t>(Kind); 11800b57cec5SDimitry Andric } 11810b57cec5SDimitry Andric } 11820b57cec5SDimitry Andric 11830b57cec5SDimitry Andric void ValueProfData::deserializeTo(InstrProfRecord &Record, 11840b57cec5SDimitry Andric InstrProfSymtab *SymTab) { 11850b57cec5SDimitry Andric if (NumValueKinds == 0) 11860b57cec5SDimitry Andric return; 11870b57cec5SDimitry Andric 11880b57cec5SDimitry Andric ValueProfRecord *VR = getFirstValueProfRecord(this); 11890b57cec5SDimitry Andric for (uint32_t K = 0; K < NumValueKinds; K++) { 11900b57cec5SDimitry Andric VR->deserializeTo(Record, SymTab); 11910b57cec5SDimitry Andric VR = getValueProfRecordNext(VR); 11920b57cec5SDimitry Andric } 11930b57cec5SDimitry Andric } 11940b57cec5SDimitry Andric 11950b57cec5SDimitry Andric static std::unique_ptr<ValueProfData> allocValueProfData(uint32_t TotalSize) { 11960b57cec5SDimitry Andric return std::unique_ptr<ValueProfData>(new (::operator new(TotalSize)) 11970b57cec5SDimitry Andric ValueProfData()); 11980b57cec5SDimitry Andric } 11990b57cec5SDimitry Andric 12000b57cec5SDimitry Andric Error ValueProfData::checkIntegrity() { 12010b57cec5SDimitry Andric if (NumValueKinds > IPVK_Last + 1) 1202349cc55cSDimitry Andric return make_error<InstrProfError>( 1203349cc55cSDimitry Andric instrprof_error::malformed, "number of value profile kinds is invalid"); 1204349cc55cSDimitry Andric // Total size needs to be multiple of quadword size. 12050b57cec5SDimitry Andric if (TotalSize % sizeof(uint64_t)) 1206349cc55cSDimitry Andric return make_error<InstrProfError>( 1207349cc55cSDimitry Andric instrprof_error::malformed, "total size is not multiples of quardword"); 12080b57cec5SDimitry Andric 12090b57cec5SDimitry Andric ValueProfRecord *VR = getFirstValueProfRecord(this); 12100b57cec5SDimitry Andric for (uint32_t K = 0; K < this->NumValueKinds; K++) { 12110b57cec5SDimitry Andric if (VR->Kind > IPVK_Last) 1212349cc55cSDimitry Andric return make_error<InstrProfError>(instrprof_error::malformed, 1213349cc55cSDimitry Andric "value kind is invalid"); 12140b57cec5SDimitry Andric VR = getValueProfRecordNext(VR); 12150b57cec5SDimitry Andric if ((char *)VR - (char *)this > (ptrdiff_t)TotalSize) 1216349cc55cSDimitry Andric return make_error<InstrProfError>( 1217349cc55cSDimitry Andric instrprof_error::malformed, 1218349cc55cSDimitry Andric "value profile address is greater than total size"); 12190b57cec5SDimitry Andric } 12200b57cec5SDimitry Andric return Error::success(); 12210b57cec5SDimitry Andric } 12220b57cec5SDimitry Andric 12230b57cec5SDimitry Andric Expected<std::unique_ptr<ValueProfData>> 12240b57cec5SDimitry Andric ValueProfData::getValueProfData(const unsigned char *D, 12250b57cec5SDimitry Andric const unsigned char *const BufferEnd, 12265f757f3fSDimitry Andric llvm::endianness Endianness) { 12270b57cec5SDimitry Andric using namespace support; 12280b57cec5SDimitry Andric 12290b57cec5SDimitry Andric if (D + sizeof(ValueProfData) > BufferEnd) 12300b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::truncated); 12310b57cec5SDimitry Andric 12320b57cec5SDimitry Andric const unsigned char *Header = D; 1233*0fca6ea1SDimitry Andric uint32_t TotalSize = endian::readNext<uint32_t>(Header, Endianness); 1234*0fca6ea1SDimitry Andric 12350b57cec5SDimitry Andric if (D + TotalSize > BufferEnd) 12360b57cec5SDimitry Andric return make_error<InstrProfError>(instrprof_error::too_large); 12370b57cec5SDimitry Andric 12380b57cec5SDimitry Andric std::unique_ptr<ValueProfData> VPD = allocValueProfData(TotalSize); 12390b57cec5SDimitry Andric memcpy(VPD.get(), D, TotalSize); 12400b57cec5SDimitry Andric // Byte swap. 12410b57cec5SDimitry Andric VPD->swapBytesToHost(Endianness); 12420b57cec5SDimitry Andric 12430b57cec5SDimitry Andric Error E = VPD->checkIntegrity(); 12440b57cec5SDimitry Andric if (E) 12450b57cec5SDimitry Andric return std::move(E); 12460b57cec5SDimitry Andric 12470b57cec5SDimitry Andric return std::move(VPD); 12480b57cec5SDimitry Andric } 12490b57cec5SDimitry Andric 12505f757f3fSDimitry Andric void ValueProfData::swapBytesToHost(llvm::endianness Endianness) { 12510b57cec5SDimitry Andric using namespace support; 12520b57cec5SDimitry Andric 12535f757f3fSDimitry Andric if (Endianness == llvm::endianness::native) 12540b57cec5SDimitry Andric return; 12550b57cec5SDimitry Andric 12560b57cec5SDimitry Andric sys::swapByteOrder<uint32_t>(TotalSize); 12570b57cec5SDimitry Andric sys::swapByteOrder<uint32_t>(NumValueKinds); 12580b57cec5SDimitry Andric 12590b57cec5SDimitry Andric ValueProfRecord *VR = getFirstValueProfRecord(this); 12600b57cec5SDimitry Andric for (uint32_t K = 0; K < NumValueKinds; K++) { 12615f757f3fSDimitry Andric VR->swapBytes(Endianness, llvm::endianness::native); 12620b57cec5SDimitry Andric VR = getValueProfRecordNext(VR); 12630b57cec5SDimitry Andric } 12640b57cec5SDimitry Andric } 12650b57cec5SDimitry Andric 12665f757f3fSDimitry Andric void ValueProfData::swapBytesFromHost(llvm::endianness Endianness) { 12670b57cec5SDimitry Andric using namespace support; 12680b57cec5SDimitry Andric 12695f757f3fSDimitry Andric if (Endianness == llvm::endianness::native) 12700b57cec5SDimitry Andric return; 12710b57cec5SDimitry Andric 12720b57cec5SDimitry Andric ValueProfRecord *VR = getFirstValueProfRecord(this); 12730b57cec5SDimitry Andric for (uint32_t K = 0; K < NumValueKinds; K++) { 12740b57cec5SDimitry Andric ValueProfRecord *NVR = getValueProfRecordNext(VR); 12755f757f3fSDimitry Andric VR->swapBytes(llvm::endianness::native, Endianness); 12760b57cec5SDimitry Andric VR = NVR; 12770b57cec5SDimitry Andric } 12780b57cec5SDimitry Andric sys::swapByteOrder<uint32_t>(TotalSize); 12790b57cec5SDimitry Andric sys::swapByteOrder<uint32_t>(NumValueKinds); 12800b57cec5SDimitry Andric } 12810b57cec5SDimitry Andric 12820b57cec5SDimitry Andric void annotateValueSite(Module &M, Instruction &Inst, 12830b57cec5SDimitry Andric const InstrProfRecord &InstrProfR, 12840b57cec5SDimitry Andric InstrProfValueKind ValueKind, uint32_t SiteIdx, 12850b57cec5SDimitry Andric uint32_t MaxMDCount) { 1286*0fca6ea1SDimitry Andric auto VDs = InstrProfR.getValueArrayForSite(ValueKind, SiteIdx); 1287*0fca6ea1SDimitry Andric if (VDs.empty()) 12880b57cec5SDimitry Andric return; 12890b57cec5SDimitry Andric uint64_t Sum = 0; 1290*0fca6ea1SDimitry Andric for (const InstrProfValueData &V : VDs) 1291*0fca6ea1SDimitry Andric Sum = SaturatingAdd(Sum, V.Count); 12920b57cec5SDimitry Andric annotateValueSite(M, Inst, VDs, Sum, ValueKind, MaxMDCount); 12930b57cec5SDimitry Andric } 12940b57cec5SDimitry Andric 12950b57cec5SDimitry Andric void annotateValueSite(Module &M, Instruction &Inst, 12960b57cec5SDimitry Andric ArrayRef<InstrProfValueData> VDs, 12970b57cec5SDimitry Andric uint64_t Sum, InstrProfValueKind ValueKind, 12980b57cec5SDimitry Andric uint32_t MaxMDCount) { 1299*0fca6ea1SDimitry Andric if (VDs.empty()) 1300*0fca6ea1SDimitry Andric return; 13010b57cec5SDimitry Andric LLVMContext &Ctx = M.getContext(); 13020b57cec5SDimitry Andric MDBuilder MDHelper(Ctx); 13030b57cec5SDimitry Andric SmallVector<Metadata *, 3> Vals; 13040b57cec5SDimitry Andric // Tag 13050b57cec5SDimitry Andric Vals.push_back(MDHelper.createString("VP")); 13060b57cec5SDimitry Andric // Value Kind 13070b57cec5SDimitry Andric Vals.push_back(MDHelper.createConstant( 13080b57cec5SDimitry Andric ConstantInt::get(Type::getInt32Ty(Ctx), ValueKind))); 13090b57cec5SDimitry Andric // Total Count 13100b57cec5SDimitry Andric Vals.push_back( 13110b57cec5SDimitry Andric MDHelper.createConstant(ConstantInt::get(Type::getInt64Ty(Ctx), Sum))); 13120b57cec5SDimitry Andric 13130b57cec5SDimitry Andric // Value Profile Data 13140b57cec5SDimitry Andric uint32_t MDCount = MaxMDCount; 1315*0fca6ea1SDimitry Andric for (const auto &VD : VDs) { 13160b57cec5SDimitry Andric Vals.push_back(MDHelper.createConstant( 13170b57cec5SDimitry Andric ConstantInt::get(Type::getInt64Ty(Ctx), VD.Value))); 13180b57cec5SDimitry Andric Vals.push_back(MDHelper.createConstant( 13190b57cec5SDimitry Andric ConstantInt::get(Type::getInt64Ty(Ctx), VD.Count))); 13200b57cec5SDimitry Andric if (--MDCount == 0) 13210b57cec5SDimitry Andric break; 13220b57cec5SDimitry Andric } 13230b57cec5SDimitry Andric Inst.setMetadata(LLVMContext::MD_prof, MDNode::get(Ctx, Vals)); 13240b57cec5SDimitry Andric } 13250b57cec5SDimitry Andric 1326*0fca6ea1SDimitry Andric MDNode *mayHaveValueProfileOfKind(const Instruction &Inst, 1327*0fca6ea1SDimitry Andric InstrProfValueKind ValueKind) { 13280b57cec5SDimitry Andric MDNode *MD = Inst.getMetadata(LLVMContext::MD_prof); 13290b57cec5SDimitry Andric if (!MD) 1330*0fca6ea1SDimitry Andric return nullptr; 13310b57cec5SDimitry Andric 1332*0fca6ea1SDimitry Andric if (MD->getNumOperands() < 5) 1333*0fca6ea1SDimitry Andric return nullptr; 13340b57cec5SDimitry Andric 13350b57cec5SDimitry Andric MDString *Tag = cast<MDString>(MD->getOperand(0)); 1336*0fca6ea1SDimitry Andric if (!Tag || Tag->getString() != "VP") 1337*0fca6ea1SDimitry Andric return nullptr; 13380b57cec5SDimitry Andric 13390b57cec5SDimitry Andric // Now check kind: 13400b57cec5SDimitry Andric ConstantInt *KindInt = mdconst::dyn_extract<ConstantInt>(MD->getOperand(1)); 13410b57cec5SDimitry Andric if (!KindInt) 1342*0fca6ea1SDimitry Andric return nullptr; 13430b57cec5SDimitry Andric if (KindInt->getZExtValue() != ValueKind) 1344*0fca6ea1SDimitry Andric return nullptr; 13450b57cec5SDimitry Andric 1346*0fca6ea1SDimitry Andric return MD; 1347*0fca6ea1SDimitry Andric } 1348*0fca6ea1SDimitry Andric 1349*0fca6ea1SDimitry Andric SmallVector<InstrProfValueData, 4> 1350*0fca6ea1SDimitry Andric getValueProfDataFromInst(const Instruction &Inst, InstrProfValueKind ValueKind, 1351*0fca6ea1SDimitry Andric uint32_t MaxNumValueData, uint64_t &TotalC, 1352*0fca6ea1SDimitry Andric bool GetNoICPValue) { 1353*0fca6ea1SDimitry Andric // Four inline elements seem to work well in practice. With MaxNumValueData, 1354*0fca6ea1SDimitry Andric // this array won't grow very big anyway. 1355*0fca6ea1SDimitry Andric SmallVector<InstrProfValueData, 4> ValueData; 1356*0fca6ea1SDimitry Andric MDNode *MD = mayHaveValueProfileOfKind(Inst, ValueKind); 1357*0fca6ea1SDimitry Andric if (!MD) 1358*0fca6ea1SDimitry Andric return ValueData; 1359*0fca6ea1SDimitry Andric const unsigned NOps = MD->getNumOperands(); 13600b57cec5SDimitry Andric // Get total count 13610b57cec5SDimitry Andric ConstantInt *TotalCInt = mdconst::dyn_extract<ConstantInt>(MD->getOperand(2)); 13620b57cec5SDimitry Andric if (!TotalCInt) 1363*0fca6ea1SDimitry Andric return ValueData; 13640b57cec5SDimitry Andric TotalC = TotalCInt->getZExtValue(); 13650b57cec5SDimitry Andric 1366*0fca6ea1SDimitry Andric ValueData.reserve((NOps - 3) / 2); 13670b57cec5SDimitry Andric for (unsigned I = 3; I < NOps; I += 2) { 1368*0fca6ea1SDimitry Andric if (ValueData.size() >= MaxNumValueData) 13690b57cec5SDimitry Andric break; 13700b57cec5SDimitry Andric ConstantInt *Value = mdconst::dyn_extract<ConstantInt>(MD->getOperand(I)); 13710b57cec5SDimitry Andric ConstantInt *Count = 13720b57cec5SDimitry Andric mdconst::dyn_extract<ConstantInt>(MD->getOperand(I + 1)); 1373*0fca6ea1SDimitry Andric if (!Value || !Count) { 1374*0fca6ea1SDimitry Andric ValueData.clear(); 1375*0fca6ea1SDimitry Andric return ValueData; 1376*0fca6ea1SDimitry Andric } 1377fe6060f1SDimitry Andric uint64_t CntValue = Count->getZExtValue(); 1378fe6060f1SDimitry Andric if (!GetNoICPValue && (CntValue == NOMORE_ICP_MAGICNUM)) 1379fe6060f1SDimitry Andric continue; 1380*0fca6ea1SDimitry Andric InstrProfValueData V; 1381*0fca6ea1SDimitry Andric V.Value = Value->getZExtValue(); 1382*0fca6ea1SDimitry Andric V.Count = CntValue; 1383*0fca6ea1SDimitry Andric ValueData.push_back(V); 13840b57cec5SDimitry Andric } 1385*0fca6ea1SDimitry Andric return ValueData; 13860b57cec5SDimitry Andric } 13870b57cec5SDimitry Andric 13880b57cec5SDimitry Andric MDNode *getPGOFuncNameMetadata(const Function &F) { 13890b57cec5SDimitry Andric return F.getMetadata(getPGOFuncNameMetadataName()); 13900b57cec5SDimitry Andric } 13910b57cec5SDimitry Andric 1392*0fca6ea1SDimitry Andric static void createPGONameMetadata(GlobalObject &GO, StringRef MetadataName, 1393*0fca6ea1SDimitry Andric StringRef PGOName) { 1394*0fca6ea1SDimitry Andric // Only for internal linkage functions or global variables. The name is not 1395*0fca6ea1SDimitry Andric // the same as PGO name for these global objects. 1396*0fca6ea1SDimitry Andric if (GO.getName() == PGOName) 13970b57cec5SDimitry Andric return; 1398*0fca6ea1SDimitry Andric 1399*0fca6ea1SDimitry Andric // Don't create duplicated metadata. 1400*0fca6ea1SDimitry Andric if (GO.getMetadata(MetadataName)) 14010b57cec5SDimitry Andric return; 1402*0fca6ea1SDimitry Andric 1403*0fca6ea1SDimitry Andric LLVMContext &C = GO.getContext(); 1404*0fca6ea1SDimitry Andric MDNode *N = MDNode::get(C, MDString::get(C, PGOName)); 1405*0fca6ea1SDimitry Andric GO.setMetadata(MetadataName, N); 14060b57cec5SDimitry Andric } 14070b57cec5SDimitry Andric 1408*0fca6ea1SDimitry Andric void createPGOFuncNameMetadata(Function &F, StringRef PGOFuncName) { 1409*0fca6ea1SDimitry Andric return createPGONameMetadata(F, getPGOFuncNameMetadataName(), PGOFuncName); 1410*0fca6ea1SDimitry Andric } 1411*0fca6ea1SDimitry Andric 1412*0fca6ea1SDimitry Andric void createPGONameMetadata(GlobalObject &GO, StringRef PGOName) { 1413*0fca6ea1SDimitry Andric return createPGONameMetadata(GO, getPGONameMetadataName(), PGOName); 1414*0fca6ea1SDimitry Andric } 1415*0fca6ea1SDimitry Andric 1416*0fca6ea1SDimitry Andric bool needsComdatForCounter(const GlobalObject &GO, const Module &M) { 1417*0fca6ea1SDimitry Andric if (GO.hasComdat()) 14180b57cec5SDimitry Andric return true; 14190b57cec5SDimitry Andric 14200b57cec5SDimitry Andric if (!Triple(M.getTargetTriple()).supportsCOMDAT()) 14210b57cec5SDimitry Andric return false; 14220b57cec5SDimitry Andric 14230b57cec5SDimitry Andric // See createPGOFuncNameVar for more details. To avoid link errors, profile 14240b57cec5SDimitry Andric // counters for function with available_externally linkage needs to be changed 14250b57cec5SDimitry Andric // to linkonce linkage. On ELF based systems, this leads to weak symbols to be 14260b57cec5SDimitry Andric // created. Without using comdat, duplicate entries won't be removed by the 14270b57cec5SDimitry Andric // linker leading to increased data segement size and raw profile size. Even 14280b57cec5SDimitry Andric // worse, since the referenced counter from profile per-function data object 14290b57cec5SDimitry Andric // will be resolved to the common strong definition, the profile counts for 14300b57cec5SDimitry Andric // available_externally functions will end up being duplicated in raw profile 14310b57cec5SDimitry Andric // data. This can result in distorted profile as the counts of those dups 14320b57cec5SDimitry Andric // will be accumulated by the profile merger. 1433*0fca6ea1SDimitry Andric GlobalValue::LinkageTypes Linkage = GO.getLinkage(); 14340b57cec5SDimitry Andric if (Linkage != GlobalValue::ExternalWeakLinkage && 14350b57cec5SDimitry Andric Linkage != GlobalValue::AvailableExternallyLinkage) 14360b57cec5SDimitry Andric return false; 14370b57cec5SDimitry Andric 14380b57cec5SDimitry Andric return true; 14390b57cec5SDimitry Andric } 14400b57cec5SDimitry Andric 14410b57cec5SDimitry Andric // Check if INSTR_PROF_RAW_VERSION_VAR is defined. 14420b57cec5SDimitry Andric bool isIRPGOFlagSet(const Module *M) { 1443*0fca6ea1SDimitry Andric const GlobalVariable *IRInstrVar = 14440b57cec5SDimitry Andric M->getNamedGlobal(INSTR_PROF_QUOTE(INSTR_PROF_RAW_VERSION_VAR)); 1445349cc55cSDimitry Andric if (!IRInstrVar || IRInstrVar->hasLocalLinkage()) 14460b57cec5SDimitry Andric return false; 14470b57cec5SDimitry Andric 1448349cc55cSDimitry Andric // For CSPGO+LTO, this variable might be marked as non-prevailing and we only 1449349cc55cSDimitry Andric // have the decl. 1450349cc55cSDimitry Andric if (IRInstrVar->isDeclaration()) 1451349cc55cSDimitry Andric return true; 1452349cc55cSDimitry Andric 14530b57cec5SDimitry Andric // Check if the flag is set. 14540b57cec5SDimitry Andric if (!IRInstrVar->hasInitializer()) 14550b57cec5SDimitry Andric return false; 14560b57cec5SDimitry Andric 14578bcb0991SDimitry Andric auto *InitVal = dyn_cast_or_null<ConstantInt>(IRInstrVar->getInitializer()); 14580b57cec5SDimitry Andric if (!InitVal) 14590b57cec5SDimitry Andric return false; 14608bcb0991SDimitry Andric return (InitVal->getZExtValue() & VARIANT_MASK_IR_PROF) != 0; 14610b57cec5SDimitry Andric } 14620b57cec5SDimitry Andric 14630b57cec5SDimitry Andric // Check if we can safely rename this Comdat function. 14640b57cec5SDimitry Andric bool canRenameComdatFunc(const Function &F, bool CheckAddressTaken) { 14650b57cec5SDimitry Andric if (F.getName().empty()) 14660b57cec5SDimitry Andric return false; 14670b57cec5SDimitry Andric if (!needsComdatForCounter(F, *(F.getParent()))) 14680b57cec5SDimitry Andric return false; 14690b57cec5SDimitry Andric // Unsafe to rename the address-taken function (which can be used in 14700b57cec5SDimitry Andric // function comparison). 14710b57cec5SDimitry Andric if (CheckAddressTaken && F.hasAddressTaken()) 14720b57cec5SDimitry Andric return false; 14730b57cec5SDimitry Andric // Only safe to do if this function may be discarded if it is not used 14740b57cec5SDimitry Andric // in the compilation unit. 14750b57cec5SDimitry Andric if (!GlobalValue::isDiscardableIfUnused(F.getLinkage())) 14760b57cec5SDimitry Andric return false; 14770b57cec5SDimitry Andric 14780b57cec5SDimitry Andric // For AvailableExternallyLinkage functions. 14790b57cec5SDimitry Andric if (!F.hasComdat()) { 14800b57cec5SDimitry Andric assert(F.getLinkage() == GlobalValue::AvailableExternallyLinkage); 14810b57cec5SDimitry Andric return true; 14820b57cec5SDimitry Andric } 14830b57cec5SDimitry Andric return true; 14840b57cec5SDimitry Andric } 14850b57cec5SDimitry Andric 14860b57cec5SDimitry Andric // Create the variable for the profile file name. 14870b57cec5SDimitry Andric void createProfileFileNameVar(Module &M, StringRef InstrProfileOutput) { 14880b57cec5SDimitry Andric if (InstrProfileOutput.empty()) 14890b57cec5SDimitry Andric return; 14900b57cec5SDimitry Andric Constant *ProfileNameConst = 14910b57cec5SDimitry Andric ConstantDataArray::getString(M.getContext(), InstrProfileOutput, true); 14920b57cec5SDimitry Andric GlobalVariable *ProfileNameVar = new GlobalVariable( 14930b57cec5SDimitry Andric M, ProfileNameConst->getType(), true, GlobalValue::WeakAnyLinkage, 14940b57cec5SDimitry Andric ProfileNameConst, INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_NAME_VAR)); 1495bdd1243dSDimitry Andric ProfileNameVar->setVisibility(GlobalValue::HiddenVisibility); 14960b57cec5SDimitry Andric Triple TT(M.getTargetTriple()); 14970b57cec5SDimitry Andric if (TT.supportsCOMDAT()) { 14980b57cec5SDimitry Andric ProfileNameVar->setLinkage(GlobalValue::ExternalLinkage); 14990b57cec5SDimitry Andric ProfileNameVar->setComdat(M.getOrInsertComdat( 15000b57cec5SDimitry Andric StringRef(INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_NAME_VAR)))); 15010b57cec5SDimitry Andric } 15020b57cec5SDimitry Andric } 15030b57cec5SDimitry Andric 15048bcb0991SDimitry Andric Error OverlapStats::accumulateCounts(const std::string &BaseFilename, 15050b57cec5SDimitry Andric const std::string &TestFilename, 15060b57cec5SDimitry Andric bool IsCS) { 1507*0fca6ea1SDimitry Andric auto GetProfileSum = [IsCS](const std::string &Filename, 15080b57cec5SDimitry Andric CountSumOrPercent &Sum) -> Error { 150906c3fb27SDimitry Andric // This function is only used from llvm-profdata that doesn't use any kind 151006c3fb27SDimitry Andric // of VFS. Just create a default RealFileSystem to read profiles. 151106c3fb27SDimitry Andric auto FS = vfs::getRealFileSystem(); 151206c3fb27SDimitry Andric auto ReaderOrErr = InstrProfReader::create(Filename, *FS); 15130b57cec5SDimitry Andric if (Error E = ReaderOrErr.takeError()) { 15140b57cec5SDimitry Andric return E; 15150b57cec5SDimitry Andric } 15160b57cec5SDimitry Andric auto Reader = std::move(ReaderOrErr.get()); 15178bcb0991SDimitry Andric Reader->accumulateCounts(Sum, IsCS); 15180b57cec5SDimitry Andric return Error::success(); 15190b57cec5SDimitry Andric }; 1520*0fca6ea1SDimitry Andric auto Ret = GetProfileSum(BaseFilename, Base); 15210b57cec5SDimitry Andric if (Ret) 15220b57cec5SDimitry Andric return Ret; 1523*0fca6ea1SDimitry Andric Ret = GetProfileSum(TestFilename, Test); 15240b57cec5SDimitry Andric if (Ret) 15250b57cec5SDimitry Andric return Ret; 15260b57cec5SDimitry Andric this->BaseFilename = &BaseFilename; 15270b57cec5SDimitry Andric this->TestFilename = &TestFilename; 15280b57cec5SDimitry Andric Valid = true; 15290b57cec5SDimitry Andric return Error::success(); 15300b57cec5SDimitry Andric } 15310b57cec5SDimitry Andric 15320b57cec5SDimitry Andric void OverlapStats::addOneMismatch(const CountSumOrPercent &MismatchFunc) { 15330b57cec5SDimitry Andric Mismatch.NumEntries += 1; 15340b57cec5SDimitry Andric Mismatch.CountSum += MismatchFunc.CountSum / Test.CountSum; 15350b57cec5SDimitry Andric for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) { 15360b57cec5SDimitry Andric if (Test.ValueCounts[I] >= 1.0f) 15370b57cec5SDimitry Andric Mismatch.ValueCounts[I] += 15380b57cec5SDimitry Andric MismatchFunc.ValueCounts[I] / Test.ValueCounts[I]; 15390b57cec5SDimitry Andric } 15400b57cec5SDimitry Andric } 15410b57cec5SDimitry Andric 15420b57cec5SDimitry Andric void OverlapStats::addOneUnique(const CountSumOrPercent &UniqueFunc) { 15430b57cec5SDimitry Andric Unique.NumEntries += 1; 15440b57cec5SDimitry Andric Unique.CountSum += UniqueFunc.CountSum / Test.CountSum; 15450b57cec5SDimitry Andric for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) { 15460b57cec5SDimitry Andric if (Test.ValueCounts[I] >= 1.0f) 15470b57cec5SDimitry Andric Unique.ValueCounts[I] += UniqueFunc.ValueCounts[I] / Test.ValueCounts[I]; 15480b57cec5SDimitry Andric } 15490b57cec5SDimitry Andric } 15500b57cec5SDimitry Andric 15510b57cec5SDimitry Andric void OverlapStats::dump(raw_fd_ostream &OS) const { 15520b57cec5SDimitry Andric if (!Valid) 15530b57cec5SDimitry Andric return; 15540b57cec5SDimitry Andric 15550b57cec5SDimitry Andric const char *EntryName = 15560b57cec5SDimitry Andric (Level == ProgramLevel ? "functions" : "edge counters"); 15570b57cec5SDimitry Andric if (Level == ProgramLevel) { 15580b57cec5SDimitry Andric OS << "Profile overlap infomation for base_profile: " << *BaseFilename 15590b57cec5SDimitry Andric << " and test_profile: " << *TestFilename << "\nProgram level:\n"; 15600b57cec5SDimitry Andric } else { 15610b57cec5SDimitry Andric OS << "Function level:\n" 15620b57cec5SDimitry Andric << " Function: " << FuncName << " (Hash=" << FuncHash << ")\n"; 15630b57cec5SDimitry Andric } 15640b57cec5SDimitry Andric 15650b57cec5SDimitry Andric OS << " # of " << EntryName << " overlap: " << Overlap.NumEntries << "\n"; 15660b57cec5SDimitry Andric if (Mismatch.NumEntries) 15670b57cec5SDimitry Andric OS << " # of " << EntryName << " mismatch: " << Mismatch.NumEntries 15680b57cec5SDimitry Andric << "\n"; 15690b57cec5SDimitry Andric if (Unique.NumEntries) 15700b57cec5SDimitry Andric OS << " # of " << EntryName 15710b57cec5SDimitry Andric << " only in test_profile: " << Unique.NumEntries << "\n"; 15720b57cec5SDimitry Andric 15730b57cec5SDimitry Andric OS << " Edge profile overlap: " << format("%.3f%%", Overlap.CountSum * 100) 15740b57cec5SDimitry Andric << "\n"; 15750b57cec5SDimitry Andric if (Mismatch.NumEntries) 15760b57cec5SDimitry Andric OS << " Mismatched count percentage (Edge): " 15770b57cec5SDimitry Andric << format("%.3f%%", Mismatch.CountSum * 100) << "\n"; 15780b57cec5SDimitry Andric if (Unique.NumEntries) 15790b57cec5SDimitry Andric OS << " Percentage of Edge profile only in test_profile: " 15800b57cec5SDimitry Andric << format("%.3f%%", Unique.CountSum * 100) << "\n"; 15810b57cec5SDimitry Andric OS << " Edge profile base count sum: " << format("%.0f", Base.CountSum) 15820b57cec5SDimitry Andric << "\n" 15830b57cec5SDimitry Andric << " Edge profile test count sum: " << format("%.0f", Test.CountSum) 15840b57cec5SDimitry Andric << "\n"; 15850b57cec5SDimitry Andric 15860b57cec5SDimitry Andric for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) { 15870b57cec5SDimitry Andric if (Base.ValueCounts[I] < 1.0f && Test.ValueCounts[I] < 1.0f) 15880b57cec5SDimitry Andric continue; 1589*0fca6ea1SDimitry Andric char ProfileKindName[20] = {0}; 15900b57cec5SDimitry Andric switch (I) { 15910b57cec5SDimitry Andric case IPVK_IndirectCallTarget: 15920b57cec5SDimitry Andric strncpy(ProfileKindName, "IndirectCall", 19); 15930b57cec5SDimitry Andric break; 15940b57cec5SDimitry Andric case IPVK_MemOPSize: 15950b57cec5SDimitry Andric strncpy(ProfileKindName, "MemOP", 19); 15960b57cec5SDimitry Andric break; 1597*0fca6ea1SDimitry Andric case IPVK_VTableTarget: 1598*0fca6ea1SDimitry Andric strncpy(ProfileKindName, "VTable", 19); 1599*0fca6ea1SDimitry Andric break; 16000b57cec5SDimitry Andric default: 16010b57cec5SDimitry Andric snprintf(ProfileKindName, 19, "VP[%d]", I); 16020b57cec5SDimitry Andric break; 16030b57cec5SDimitry Andric } 16040b57cec5SDimitry Andric OS << " " << ProfileKindName 16050b57cec5SDimitry Andric << " profile overlap: " << format("%.3f%%", Overlap.ValueCounts[I] * 100) 16060b57cec5SDimitry Andric << "\n"; 16070b57cec5SDimitry Andric if (Mismatch.NumEntries) 16080b57cec5SDimitry Andric OS << " Mismatched count percentage (" << ProfileKindName 16090b57cec5SDimitry Andric << "): " << format("%.3f%%", Mismatch.ValueCounts[I] * 100) << "\n"; 16100b57cec5SDimitry Andric if (Unique.NumEntries) 16110b57cec5SDimitry Andric OS << " Percentage of " << ProfileKindName 16120b57cec5SDimitry Andric << " profile only in test_profile: " 16130b57cec5SDimitry Andric << format("%.3f%%", Unique.ValueCounts[I] * 100) << "\n"; 16140b57cec5SDimitry Andric OS << " " << ProfileKindName 16150b57cec5SDimitry Andric << " profile base count sum: " << format("%.0f", Base.ValueCounts[I]) 16160b57cec5SDimitry Andric << "\n" 16170b57cec5SDimitry Andric << " " << ProfileKindName 16180b57cec5SDimitry Andric << " profile test count sum: " << format("%.0f", Test.ValueCounts[I]) 16190b57cec5SDimitry Andric << "\n"; 16200b57cec5SDimitry Andric } 16210b57cec5SDimitry Andric } 16220b57cec5SDimitry Andric 162381ad6265SDimitry Andric namespace IndexedInstrProf { 162481ad6265SDimitry Andric Expected<Header> Header::readFromBuffer(const unsigned char *Buffer) { 162581ad6265SDimitry Andric using namespace support; 1626bdd1243dSDimitry Andric static_assert(std::is_standard_layout_v<Header>, 1627*0fca6ea1SDimitry Andric "Use standard layout for Header for simplicity"); 162881ad6265SDimitry Andric Header H; 162981ad6265SDimitry Andric 1630*0fca6ea1SDimitry Andric H.Magic = endian::readNext<uint64_t, llvm::endianness::little>(Buffer); 163181ad6265SDimitry Andric // Check the magic number. 1632*0fca6ea1SDimitry Andric if (H.Magic != IndexedInstrProf::Magic) 163381ad6265SDimitry Andric return make_error<InstrProfError>(instrprof_error::bad_magic); 163481ad6265SDimitry Andric 163581ad6265SDimitry Andric // Read the version. 1636*0fca6ea1SDimitry Andric H.Version = endian::readNext<uint64_t, llvm::endianness::little>(Buffer); 1637*0fca6ea1SDimitry Andric if (H.getIndexedProfileVersion() > 163881ad6265SDimitry Andric IndexedInstrProf::ProfVersion::CurrentVersion) 163981ad6265SDimitry Andric return make_error<InstrProfError>(instrprof_error::unsupported_version); 164081ad6265SDimitry Andric 1641*0fca6ea1SDimitry Andric static_assert(IndexedInstrProf::ProfVersion::CurrentVersion == Version12, 1642*0fca6ea1SDimitry Andric "Please update the reader as needed when a new field is added " 1643*0fca6ea1SDimitry Andric "or when indexed profile version gets bumped."); 164481ad6265SDimitry Andric 1645*0fca6ea1SDimitry Andric Buffer += sizeof(uint64_t); // Skip Header.Unused field. 1646*0fca6ea1SDimitry Andric H.HashType = endian::readNext<uint64_t, llvm::endianness::little>(Buffer); 1647*0fca6ea1SDimitry Andric H.HashOffset = endian::readNext<uint64_t, llvm::endianness::little>(Buffer); 1648*0fca6ea1SDimitry Andric if (H.getIndexedProfileVersion() >= 8) 1649*0fca6ea1SDimitry Andric H.MemProfOffset = 1650*0fca6ea1SDimitry Andric endian::readNext<uint64_t, llvm::endianness::little>(Buffer); 1651*0fca6ea1SDimitry Andric if (H.getIndexedProfileVersion() >= 9) 1652*0fca6ea1SDimitry Andric H.BinaryIdOffset = 1653*0fca6ea1SDimitry Andric endian::readNext<uint64_t, llvm::endianness::little>(Buffer); 1654*0fca6ea1SDimitry Andric // Version 11 is handled by this condition. 1655*0fca6ea1SDimitry Andric if (H.getIndexedProfileVersion() >= 10) 1656*0fca6ea1SDimitry Andric H.TemporalProfTracesOffset = 1657*0fca6ea1SDimitry Andric endian::readNext<uint64_t, llvm::endianness::little>(Buffer); 1658*0fca6ea1SDimitry Andric if (H.getIndexedProfileVersion() >= 12) 1659*0fca6ea1SDimitry Andric H.VTableNamesOffset = 1660*0fca6ea1SDimitry Andric endian::readNext<uint64_t, llvm::endianness::little>(Buffer); 166181ad6265SDimitry Andric return H; 166281ad6265SDimitry Andric } 166381ad6265SDimitry Andric 1664*0fca6ea1SDimitry Andric uint64_t Header::getIndexedProfileVersion() const { 1665*0fca6ea1SDimitry Andric return GET_VERSION(Version); 1666*0fca6ea1SDimitry Andric } 1667*0fca6ea1SDimitry Andric 166881ad6265SDimitry Andric size_t Header::size() const { 1669*0fca6ea1SDimitry Andric switch (getIndexedProfileVersion()) { 1670*0fca6ea1SDimitry Andric // To retain backward compatibility, new fields must be appended to the end 1671*0fca6ea1SDimitry Andric // of the header, and byte offset of existing fields shouldn't change when 1672*0fca6ea1SDimitry Andric // indexed profile version gets incremented. 1673*0fca6ea1SDimitry Andric static_assert( 1674*0fca6ea1SDimitry Andric IndexedInstrProf::ProfVersion::CurrentVersion == Version12, 167581ad6265SDimitry Andric "Please update the size computation below if a new field has " 1676*0fca6ea1SDimitry Andric "been added to the header; for a version bump without new " 1677*0fca6ea1SDimitry Andric "fields, add a case statement to fall through to the latest version."); 1678*0fca6ea1SDimitry Andric case 12ull: 1679*0fca6ea1SDimitry Andric return 72; 16805f757f3fSDimitry Andric case 11ull: 16815f757f3fSDimitry Andric [[fallthrough]]; 168206c3fb27SDimitry Andric case 10ull: 1683*0fca6ea1SDimitry Andric return 64; 1684bdd1243dSDimitry Andric case 9ull: 1685*0fca6ea1SDimitry Andric return 56; 168681ad6265SDimitry Andric case 8ull: 1687*0fca6ea1SDimitry Andric return 48; 168881ad6265SDimitry Andric default: // Version7 (when the backwards compatible header was introduced). 1689*0fca6ea1SDimitry Andric return 40; 169081ad6265SDimitry Andric } 169181ad6265SDimitry Andric } 169281ad6265SDimitry Andric 169381ad6265SDimitry Andric } // namespace IndexedInstrProf 169481ad6265SDimitry Andric 16950b57cec5SDimitry Andric } // end namespace llvm 1696