xref: /llvm-project/llvm/lib/ProfileData/InstrProfCorrelator.cpp (revision 787cd8f0fee8659335b0ed501d6896275d936f3d)
165d7fd02SEllis Hoag //===-- InstrProfCorrelator.cpp -------------------------------------------===//
265d7fd02SEllis Hoag //
365d7fd02SEllis Hoag // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
465d7fd02SEllis Hoag // See https://llvm.org/LICENSE.txt for license information.
565d7fd02SEllis Hoag // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
665d7fd02SEllis Hoag //
765d7fd02SEllis Hoag //===----------------------------------------------------------------------===//
865d7fd02SEllis Hoag 
965d7fd02SEllis Hoag #include "llvm/ProfileData/InstrProfCorrelator.h"
10fc97efa4Sserge-sans-paille #include "llvm/DebugInfo/DIContext.h"
11fc97efa4Sserge-sans-paille #include "llvm/DebugInfo/DWARF/DWARFContext.h"
12fc97efa4Sserge-sans-paille #include "llvm/DebugInfo/DWARF/DWARFDie.h"
13290e4823Sserge-sans-paille #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
14fc97efa4Sserge-sans-paille #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
15fc97efa4Sserge-sans-paille #include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h"
16fc97efa4Sserge-sans-paille #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
1765d7fd02SEllis Hoag #include "llvm/Object/MachO.h"
1865d7fd02SEllis Hoag #include "llvm/Support/Debug.h"
19d687caaeSEllis Hoag #include "llvm/Support/Format.h"
20d687caaeSEllis Hoag #include "llvm/Support/WithColor.h"
21c589730aSKrzysztof Parzyszek #include <optional>
2265d7fd02SEllis Hoag 
2365d7fd02SEllis Hoag #define DEBUG_TYPE "correlator"
2465d7fd02SEllis Hoag 
2565d7fd02SEllis Hoag using namespace llvm;
2665d7fd02SEllis Hoag 
273c97c8b6SZequan Wu /// Get profile section.
283c97c8b6SZequan Wu Expected<object::SectionRef> getInstrProfSection(const object::ObjectFile &Obj,
293c97c8b6SZequan Wu                                                  InstrProfSectKind IPSK) {
30ab3430f8SZequan Wu   // On COFF, the getInstrProfSectionName returns the section names may followed
31ab3430f8SZequan Wu   // by "$M". The linker removes the dollar and everything after it in the final
32ab3430f8SZequan Wu   // binary. Do the same to match.
333c97c8b6SZequan Wu   Triple::ObjectFormatType ObjFormat = Obj.getTripleObjectFormat();
34ab3430f8SZequan Wu   auto StripSuffix = [ObjFormat](StringRef N) {
35ab3430f8SZequan Wu     return ObjFormat == Triple::COFF ? N.split('$').first : N;
36ab3430f8SZequan Wu   };
373c97c8b6SZequan Wu   std::string ExpectedSectionName =
383c97c8b6SZequan Wu       getInstrProfSectionName(IPSK, ObjFormat,
393c97c8b6SZequan Wu                               /*AddSegmentInfo=*/false);
40ab3430f8SZequan Wu   ExpectedSectionName = StripSuffix(ExpectedSectionName);
41ab3430f8SZequan Wu   for (auto &Section : Obj.sections()) {
4265d7fd02SEllis Hoag     if (auto SectionName = Section.getName())
43ab3430f8SZequan Wu       if (*SectionName == ExpectedSectionName)
4465d7fd02SEllis Hoag         return Section;
45ab3430f8SZequan Wu   }
4665d7fd02SEllis Hoag   return make_error<InstrProfError>(
476d523911SEllis Hoag       instrprof_error::unable_to_correlate_profile,
483c97c8b6SZequan Wu       "could not find section (" + Twine(ExpectedSectionName) + ")");
4965d7fd02SEllis Hoag }
5065d7fd02SEllis Hoag 
5165d7fd02SEllis Hoag const char *InstrProfCorrelator::FunctionNameAttributeName = "Function Name";
5265d7fd02SEllis Hoag const char *InstrProfCorrelator::CFGHashAttributeName = "CFG Hash";
5365d7fd02SEllis Hoag const char *InstrProfCorrelator::NumCountersAttributeName = "Num Counters";
5465d7fd02SEllis Hoag 
5565d7fd02SEllis Hoag llvm::Expected<std::unique_ptr<InstrProfCorrelator::Context>>
5665d7fd02SEllis Hoag InstrProfCorrelator::Context::get(std::unique_ptr<MemoryBuffer> Buffer,
57ab3430f8SZequan Wu                                   const object::ObjectFile &Obj,
58ab3430f8SZequan Wu                                   ProfCorrelatorKind FileKind) {
59ab3430f8SZequan Wu   auto C = std::make_unique<Context>();
603c97c8b6SZequan Wu   auto CountersSection = getInstrProfSection(Obj, IPSK_cnts);
6165d7fd02SEllis Hoag   if (auto Err = CountersSection.takeError())
6265d7fd02SEllis Hoag     return std::move(Err);
63ab3430f8SZequan Wu   if (FileKind == InstrProfCorrelator::BINARY) {
64ab3430f8SZequan Wu     auto DataSection = getInstrProfSection(Obj, IPSK_covdata);
65ab3430f8SZequan Wu     if (auto Err = DataSection.takeError())
66ab3430f8SZequan Wu       return std::move(Err);
67ab3430f8SZequan Wu     auto DataOrErr = DataSection->getContents();
68ab3430f8SZequan Wu     if (!DataOrErr)
69ab3430f8SZequan Wu       return DataOrErr.takeError();
70ab3430f8SZequan Wu     auto NameSection = getInstrProfSection(Obj, IPSK_covname);
71ab3430f8SZequan Wu     if (auto Err = NameSection.takeError())
72ab3430f8SZequan Wu       return std::move(Err);
73ab3430f8SZequan Wu     auto NameOrErr = NameSection->getContents();
74ab3430f8SZequan Wu     if (!NameOrErr)
75ab3430f8SZequan Wu       return NameOrErr.takeError();
76ab3430f8SZequan Wu     C->DataStart = DataOrErr->data();
77ab3430f8SZequan Wu     C->DataEnd = DataOrErr->data() + DataOrErr->size();
78ab3430f8SZequan Wu     C->NameStart = NameOrErr->data();
79ab3430f8SZequan Wu     C->NameSize = NameOrErr->size();
80ab3430f8SZequan Wu   }
8165d7fd02SEllis Hoag   C->Buffer = std::move(Buffer);
8265d7fd02SEllis Hoag   C->CountersSectionStart = CountersSection->getAddress();
8365d7fd02SEllis Hoag   C->CountersSectionEnd = C->CountersSectionStart + CountersSection->getSize();
84ab3430f8SZequan Wu   // In COFF object file, there's a null byte at the beginning of the counter
85ab3430f8SZequan Wu   // section which doesn't exist in raw profile.
86ab3430f8SZequan Wu   if (Obj.getTripleObjectFormat() == Triple::COFF)
87ab3430f8SZequan Wu     ++C->CountersSectionStart;
88ab3430f8SZequan Wu 
8965d7fd02SEllis Hoag   C->ShouldSwapBytes = Obj.isLittleEndian() != sys::IsLittleEndianHost;
9065d7fd02SEllis Hoag   return Expected<std::unique_ptr<Context>>(std::move(C));
9165d7fd02SEllis Hoag }
9265d7fd02SEllis Hoag 
9365d7fd02SEllis Hoag llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
94*787cd8f0Sgulfemsavrun InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind,
95*787cd8f0Sgulfemsavrun                          const object::BuildIDFetcher *BIDFetcher,
96*787cd8f0Sgulfemsavrun                          const ArrayRef<object::BuildID> BIs) {
97*787cd8f0Sgulfemsavrun   std::optional<std::string> Path;
98*787cd8f0Sgulfemsavrun   if (BIDFetcher) {
99*787cd8f0Sgulfemsavrun     if (BIs.empty())
100*787cd8f0Sgulfemsavrun       return make_error<InstrProfError>(
101*787cd8f0Sgulfemsavrun           instrprof_error::unable_to_correlate_profile,
102*787cd8f0Sgulfemsavrun           "unsupported profile binary correlation when there is no build ID "
103*787cd8f0Sgulfemsavrun           "in a profile");
104*787cd8f0Sgulfemsavrun     if (BIs.size() > 1)
105*787cd8f0Sgulfemsavrun       return make_error<InstrProfError>(
106*787cd8f0Sgulfemsavrun           instrprof_error::unable_to_correlate_profile,
107*787cd8f0Sgulfemsavrun           "unsupported profile binary correlation when there are multiple "
108*787cd8f0Sgulfemsavrun           "build IDs in a profile");
109*787cd8f0Sgulfemsavrun 
110*787cd8f0Sgulfemsavrun     Path = BIDFetcher->fetch(BIs.front());
111*787cd8f0Sgulfemsavrun     if (!Path)
112*787cd8f0Sgulfemsavrun       return make_error<InstrProfError>(
113*787cd8f0Sgulfemsavrun           instrprof_error::unable_to_correlate_profile,
114*787cd8f0Sgulfemsavrun           "Missing build ID: " + llvm::toHex(BIs.front(),
115*787cd8f0Sgulfemsavrun                                              /*LowerCase=*/true));
116*787cd8f0Sgulfemsavrun     Filename = *Path;
117*787cd8f0Sgulfemsavrun   }
118*787cd8f0Sgulfemsavrun 
1193c97c8b6SZequan Wu   if (FileKind == DEBUG_INFO) {
12065d7fd02SEllis Hoag     auto DsymObjectsOrErr =
1213c97c8b6SZequan Wu         object::MachOObjectFile::findDsymObjectMembers(Filename);
12265d7fd02SEllis Hoag     if (auto Err = DsymObjectsOrErr.takeError())
12365d7fd02SEllis Hoag       return std::move(Err);
12465d7fd02SEllis Hoag     if (!DsymObjectsOrErr->empty()) {
12565d7fd02SEllis Hoag       // TODO: Enable profile correlation when there are multiple objects in a
12665d7fd02SEllis Hoag       // dSYM bundle.
12765d7fd02SEllis Hoag       if (DsymObjectsOrErr->size() > 1)
1286d523911SEllis Hoag         return make_error<InstrProfError>(
1296d523911SEllis Hoag             instrprof_error::unable_to_correlate_profile,
1306d523911SEllis Hoag             "using multiple objects is not yet supported");
1313c97c8b6SZequan Wu       Filename = *DsymObjectsOrErr->begin();
13265d7fd02SEllis Hoag     }
1333c97c8b6SZequan Wu     auto BufferOrErr = errorOrToExpected(MemoryBuffer::getFile(Filename));
13465d7fd02SEllis Hoag     if (auto Err = BufferOrErr.takeError())
13565d7fd02SEllis Hoag       return std::move(Err);
13665d7fd02SEllis Hoag 
1373c97c8b6SZequan Wu     return get(std::move(*BufferOrErr), FileKind);
13865d7fd02SEllis Hoag   }
139ab3430f8SZequan Wu   if (FileKind == BINARY) {
140ab3430f8SZequan Wu     auto BufferOrErr = errorOrToExpected(MemoryBuffer::getFile(Filename));
141ab3430f8SZequan Wu     if (auto Err = BufferOrErr.takeError())
142ab3430f8SZequan Wu       return std::move(Err);
143ab3430f8SZequan Wu 
144ab3430f8SZequan Wu     return get(std::move(*BufferOrErr), FileKind);
145ab3430f8SZequan Wu   }
14656e205a8SZequan Wu   return make_error<InstrProfError>(
14756e205a8SZequan Wu       instrprof_error::unable_to_correlate_profile,
148ab3430f8SZequan Wu       "unsupported correlation kind (only DWARF debug info and Binary format "
149ab3430f8SZequan Wu       "(ELF/COFF) are supported)");
15056e205a8SZequan Wu }
15165d7fd02SEllis Hoag 
15265d7fd02SEllis Hoag llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
1533c97c8b6SZequan Wu InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer,
1543c97c8b6SZequan Wu                          ProfCorrelatorKind FileKind) {
15565d7fd02SEllis Hoag   auto BinOrErr = object::createBinary(*Buffer);
15665d7fd02SEllis Hoag   if (auto Err = BinOrErr.takeError())
15765d7fd02SEllis Hoag     return std::move(Err);
15865d7fd02SEllis Hoag 
15965d7fd02SEllis Hoag   if (auto *Obj = dyn_cast<object::ObjectFile>(BinOrErr->get())) {
160ab3430f8SZequan Wu     auto CtxOrErr = Context::get(std::move(Buffer), *Obj, FileKind);
16165d7fd02SEllis Hoag     if (auto Err = CtxOrErr.takeError())
16265d7fd02SEllis Hoag       return std::move(Err);
16365d7fd02SEllis Hoag     auto T = Obj->makeTriple();
16465d7fd02SEllis Hoag     if (T.isArch64Bit())
1653c97c8b6SZequan Wu       return InstrProfCorrelatorImpl<uint64_t>::get(std::move(*CtxOrErr), *Obj,
1663c97c8b6SZequan Wu                                                     FileKind);
16765d7fd02SEllis Hoag     if (T.isArch32Bit())
1683c97c8b6SZequan Wu       return InstrProfCorrelatorImpl<uint32_t>::get(std::move(*CtxOrErr), *Obj,
1693c97c8b6SZequan Wu                                                     FileKind);
17065d7fd02SEllis Hoag   }
17165d7fd02SEllis Hoag   return make_error<InstrProfError>(
1726d523911SEllis Hoag       instrprof_error::unable_to_correlate_profile, "not an object file");
17365d7fd02SEllis Hoag }
17465d7fd02SEllis Hoag 
1754e0e0bbdSFangrui Song std::optional<size_t> InstrProfCorrelator::getDataSize() const {
176c9baa560SEllis Hoag   if (auto *C = dyn_cast<InstrProfCorrelatorImpl<uint32_t>>(this)) {
177c9baa560SEllis Hoag     return C->getDataSize();
178c9baa560SEllis Hoag   } else if (auto *C = dyn_cast<InstrProfCorrelatorImpl<uint64_t>>(this)) {
179c9baa560SEllis Hoag     return C->getDataSize();
180c9baa560SEllis Hoag   }
181c9baa560SEllis Hoag   return {};
182c9baa560SEllis Hoag }
183c9baa560SEllis Hoag 
18465d7fd02SEllis Hoag namespace llvm {
18565d7fd02SEllis Hoag 
18665d7fd02SEllis Hoag template <>
18765d7fd02SEllis Hoag InstrProfCorrelatorImpl<uint32_t>::InstrProfCorrelatorImpl(
18865d7fd02SEllis Hoag     std::unique_ptr<InstrProfCorrelator::Context> Ctx)
18965d7fd02SEllis Hoag     : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_32Bit,
19065d7fd02SEllis Hoag                               std::move(Ctx)) {}
19165d7fd02SEllis Hoag template <>
19265d7fd02SEllis Hoag InstrProfCorrelatorImpl<uint64_t>::InstrProfCorrelatorImpl(
19365d7fd02SEllis Hoag     std::unique_ptr<InstrProfCorrelator::Context> Ctx)
19465d7fd02SEllis Hoag     : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_64Bit,
19565d7fd02SEllis Hoag                               std::move(Ctx)) {}
19665d7fd02SEllis Hoag template <>
19765d7fd02SEllis Hoag bool InstrProfCorrelatorImpl<uint32_t>::classof(const InstrProfCorrelator *C) {
19865d7fd02SEllis Hoag   return C->getKind() == InstrProfCorrelatorKind::CK_32Bit;
19965d7fd02SEllis Hoag }
20065d7fd02SEllis Hoag template <>
20165d7fd02SEllis Hoag bool InstrProfCorrelatorImpl<uint64_t>::classof(const InstrProfCorrelator *C) {
20265d7fd02SEllis Hoag   return C->getKind() == InstrProfCorrelatorKind::CK_64Bit;
20365d7fd02SEllis Hoag }
20465d7fd02SEllis Hoag 
20565d7fd02SEllis Hoag } // end namespace llvm
20665d7fd02SEllis Hoag 
20765d7fd02SEllis Hoag template <class IntPtrT>
20865d7fd02SEllis Hoag llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>>
20965d7fd02SEllis Hoag InstrProfCorrelatorImpl<IntPtrT>::get(
21065d7fd02SEllis Hoag     std::unique_ptr<InstrProfCorrelator::Context> Ctx,
2113c97c8b6SZequan Wu     const object::ObjectFile &Obj, ProfCorrelatorKind FileKind) {
2123c97c8b6SZequan Wu   if (FileKind == DEBUG_INFO) {
21365d7fd02SEllis Hoag     if (Obj.isELF() || Obj.isMachO()) {
21465d7fd02SEllis Hoag       auto DICtx = DWARFContext::create(Obj);
2153c97c8b6SZequan Wu       return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>(
2163c97c8b6SZequan Wu           std::move(DICtx), std::move(Ctx));
21765d7fd02SEllis Hoag     }
2186d523911SEllis Hoag     return make_error<InstrProfError>(
2196d523911SEllis Hoag         instrprof_error::unable_to_correlate_profile,
2206d523911SEllis Hoag         "unsupported debug info format (only DWARF is supported)");
22165d7fd02SEllis Hoag   }
222ab3430f8SZequan Wu   if (Obj.isELF() || Obj.isCOFF())
223ab3430f8SZequan Wu     return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(std::move(Ctx));
2243c97c8b6SZequan Wu   return make_error<InstrProfError>(
2253c97c8b6SZequan Wu       instrprof_error::unable_to_correlate_profile,
226ab3430f8SZequan Wu       "unsupported binary format (only ELF and COFF are supported)");
2273c97c8b6SZequan Wu }
22865d7fd02SEllis Hoag 
22965d7fd02SEllis Hoag template <class IntPtrT>
230d687caaeSEllis Hoag Error InstrProfCorrelatorImpl<IntPtrT>::correlateProfileData(int MaxWarnings) {
231f1705952SEllis Hoag   assert(Data.empty() && Names.empty() && NamesVec.empty());
232d687caaeSEllis Hoag   correlateProfileDataImpl(MaxWarnings);
2333c97c8b6SZequan Wu   if (this->Data.empty())
2346d523911SEllis Hoag     return make_error<InstrProfError>(
2356d523911SEllis Hoag         instrprof_error::unable_to_correlate_profile,
2363c97c8b6SZequan Wu         "could not find any profile data metadata in correlated file");
2373c97c8b6SZequan Wu   Error Result = correlateProfileNameImpl();
2383c97c8b6SZequan Wu   this->CounterOffsets.clear();
2393c97c8b6SZequan Wu   this->NamesVec.clear();
24065d7fd02SEllis Hoag   return Result;
24165d7fd02SEllis Hoag }
24265d7fd02SEllis Hoag 
24370fb7bb5SEllis Hoag template <> struct yaml::MappingTraits<InstrProfCorrelator::CorrelationData> {
24470fb7bb5SEllis Hoag   static void mapping(yaml::IO &io,
24570fb7bb5SEllis Hoag                       InstrProfCorrelator::CorrelationData &Data) {
24670fb7bb5SEllis Hoag     io.mapRequired("Probes", Data.Probes);
24770fb7bb5SEllis Hoag   }
24870fb7bb5SEllis Hoag };
24970fb7bb5SEllis Hoag 
25070fb7bb5SEllis Hoag template <> struct yaml::MappingTraits<InstrProfCorrelator::Probe> {
25170fb7bb5SEllis Hoag   static void mapping(yaml::IO &io, InstrProfCorrelator::Probe &P) {
25270fb7bb5SEllis Hoag     io.mapRequired("Function Name", P.FunctionName);
25370fb7bb5SEllis Hoag     io.mapOptional("Linkage Name", P.LinkageName);
25470fb7bb5SEllis Hoag     io.mapRequired("CFG Hash", P.CFGHash);
25570fb7bb5SEllis Hoag     io.mapRequired("Counter Offset", P.CounterOffset);
25670fb7bb5SEllis Hoag     io.mapRequired("Num Counters", P.NumCounters);
25770fb7bb5SEllis Hoag     io.mapOptional("File", P.FilePath);
25870fb7bb5SEllis Hoag     io.mapOptional("Line", P.LineNumber);
25970fb7bb5SEllis Hoag   }
26070fb7bb5SEllis Hoag };
26170fb7bb5SEllis Hoag 
26270fb7bb5SEllis Hoag template <> struct yaml::SequenceElementTraits<InstrProfCorrelator::Probe> {
26370fb7bb5SEllis Hoag   static const bool flow = false;
26470fb7bb5SEllis Hoag };
26570fb7bb5SEllis Hoag 
26670fb7bb5SEllis Hoag template <class IntPtrT>
267d687caaeSEllis Hoag Error InstrProfCorrelatorImpl<IntPtrT>::dumpYaml(int MaxWarnings,
268d687caaeSEllis Hoag                                                  raw_ostream &OS) {
26970fb7bb5SEllis Hoag   InstrProfCorrelator::CorrelationData Data;
270d687caaeSEllis Hoag   correlateProfileDataImpl(MaxWarnings, &Data);
27170fb7bb5SEllis Hoag   if (Data.Probes.empty())
27270fb7bb5SEllis Hoag     return make_error<InstrProfError>(
27370fb7bb5SEllis Hoag         instrprof_error::unable_to_correlate_profile,
2743c97c8b6SZequan Wu         "could not find any profile data metadata in debug info");
27570fb7bb5SEllis Hoag   yaml::Output YamlOS(OS);
27670fb7bb5SEllis Hoag   YamlOS << Data;
27770fb7bb5SEllis Hoag   return Error::success();
27870fb7bb5SEllis Hoag }
27970fb7bb5SEllis Hoag 
28065d7fd02SEllis Hoag template <class IntPtrT>
281ab3430f8SZequan Wu void InstrProfCorrelatorImpl<IntPtrT>::addDataProbe(uint64_t NameRef,
28265d7fd02SEllis Hoag                                                     uint64_t CFGHash,
28365d7fd02SEllis Hoag                                                     IntPtrT CounterOffset,
28465d7fd02SEllis Hoag                                                     IntPtrT FunctionPtr,
28565d7fd02SEllis Hoag                                                     uint32_t NumCounters) {
28618ffb5dcSEllis Hoag   // Check if a probe was already added for this counter offset.
28718ffb5dcSEllis Hoag   if (!CounterOffsets.insert(CounterOffset).second)
28818ffb5dcSEllis Hoag     return;
28965d7fd02SEllis Hoag   Data.push_back({
290ab3430f8SZequan Wu       maybeSwap<uint64_t>(NameRef),
29165d7fd02SEllis Hoag       maybeSwap<uint64_t>(CFGHash),
29265d7fd02SEllis Hoag       // In this mode, CounterPtr actually stores the section relative address
29365d7fd02SEllis Hoag       // of the counter.
29465d7fd02SEllis Hoag       maybeSwap<IntPtrT>(CounterOffset),
295f95b2f1aSAlan Phipps       // TODO: MC/DC is not yet supported.
296f95b2f1aSAlan Phipps       /*BitmapOffset=*/maybeSwap<IntPtrT>(0),
29765d7fd02SEllis Hoag       maybeSwap<IntPtrT>(FunctionPtr),
29865d7fd02SEllis Hoag       // TODO: Value profiling is not yet supported.
29965d7fd02SEllis Hoag       /*ValuesPtr=*/maybeSwap<IntPtrT>(0),
30065d7fd02SEllis Hoag       maybeSwap<uint32_t>(NumCounters),
30165d7fd02SEllis Hoag       /*NumValueSites=*/{maybeSwap<uint16_t>(0), maybeSwap<uint16_t>(0)},
302f95b2f1aSAlan Phipps       // TODO: MC/DC is not yet supported.
303f95b2f1aSAlan Phipps       /*NumBitmapBytes=*/maybeSwap<uint32_t>(0),
30465d7fd02SEllis Hoag   });
30565d7fd02SEllis Hoag }
30665d7fd02SEllis Hoag 
30765d7fd02SEllis Hoag template <class IntPtrT>
3084e0e0bbdSFangrui Song std::optional<uint64_t>
30965d7fd02SEllis Hoag DwarfInstrProfCorrelator<IntPtrT>::getLocation(const DWARFDie &Die) const {
31065d7fd02SEllis Hoag   auto Locations = Die.getLocations(dwarf::DW_AT_location);
31165d7fd02SEllis Hoag   if (!Locations) {
31265d7fd02SEllis Hoag     consumeError(Locations.takeError());
31365d7fd02SEllis Hoag     return {};
31465d7fd02SEllis Hoag   }
31565d7fd02SEllis Hoag   auto &DU = *Die.getDwarfUnit();
31665d7fd02SEllis Hoag   auto AddressSize = DU.getAddressByteSize();
3179c2891a8SEllis Hoag   for (auto &Location : *Locations) {
31865d7fd02SEllis Hoag     DataExtractor Data(Location.Expr, DICtx->isLittleEndian(), AddressSize);
31965d7fd02SEllis Hoag     DWARFExpression Expr(Data, AddressSize);
3209c2891a8SEllis Hoag     for (auto &Op : Expr) {
3219c2891a8SEllis Hoag       if (Op.getCode() == dwarf::DW_OP_addr) {
32265d7fd02SEllis Hoag         return Op.getRawOperand(0);
3239c2891a8SEllis Hoag       } else if (Op.getCode() == dwarf::DW_OP_addrx) {
3249c2891a8SEllis Hoag         uint64_t Index = Op.getRawOperand(0);
3259c2891a8SEllis Hoag         if (auto SA = DU.getAddrOffsetSectionItem(Index))
3269c2891a8SEllis Hoag           return SA->Address;
3279c2891a8SEllis Hoag       }
3289c2891a8SEllis Hoag     }
32965d7fd02SEllis Hoag   }
33065d7fd02SEllis Hoag   return {};
33165d7fd02SEllis Hoag }
33265d7fd02SEllis Hoag 
33365d7fd02SEllis Hoag template <class IntPtrT>
33465d7fd02SEllis Hoag bool DwarfInstrProfCorrelator<IntPtrT>::isDIEOfProbe(const DWARFDie &Die) {
33565d7fd02SEllis Hoag   const auto &ParentDie = Die.getParent();
33665d7fd02SEllis Hoag   if (!Die.isValid() || !ParentDie.isValid() || Die.isNULL())
33765d7fd02SEllis Hoag     return false;
33865d7fd02SEllis Hoag   if (Die.getTag() != dwarf::DW_TAG_variable)
33965d7fd02SEllis Hoag     return false;
34065d7fd02SEllis Hoag   if (!ParentDie.isSubprogramDIE())
34165d7fd02SEllis Hoag     return false;
34265d7fd02SEllis Hoag   if (!Die.hasChildren())
34365d7fd02SEllis Hoag     return false;
34465d7fd02SEllis Hoag   if (const char *Name = Die.getName(DINameKind::ShortName))
345586ecdf2SKazu Hirata     return StringRef(Name).starts_with(getInstrProfCountersVarPrefix());
34665d7fd02SEllis Hoag   return false;
34765d7fd02SEllis Hoag }
34865d7fd02SEllis Hoag 
34965d7fd02SEllis Hoag template <class IntPtrT>
35070fb7bb5SEllis Hoag void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
351d687caaeSEllis Hoag     int MaxWarnings, InstrProfCorrelator::CorrelationData *Data) {
352d687caaeSEllis Hoag   bool UnlimitedWarnings = (MaxWarnings == 0);
353d687caaeSEllis Hoag   // -N suppressed warnings means we can emit up to N (unsuppressed) warnings
354d687caaeSEllis Hoag   int NumSuppressedWarnings = -MaxWarnings;
35565d7fd02SEllis Hoag   auto maybeAddProbe = [&](DWARFDie Die) {
35665d7fd02SEllis Hoag     if (!isDIEOfProbe(Die))
35765d7fd02SEllis Hoag       return;
35818fd2aa3SKazu Hirata     std::optional<const char *> FunctionName;
35989fab98eSFangrui Song     std::optional<uint64_t> CFGHash;
3604e0e0bbdSFangrui Song     std::optional<uint64_t> CounterPtr = getLocation(Die);
36170fb7bb5SEllis Hoag     auto FnDie = Die.getParent();
36270fb7bb5SEllis Hoag     auto FunctionPtr = dwarf::toAddress(FnDie.find(dwarf::DW_AT_low_pc));
36389fab98eSFangrui Song     std::optional<uint64_t> NumCounters;
36465d7fd02SEllis Hoag     for (const DWARFDie &Child : Die.children()) {
36565d7fd02SEllis Hoag       if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
36665d7fd02SEllis Hoag         continue;
36765d7fd02SEllis Hoag       auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
36865d7fd02SEllis Hoag       auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
36965d7fd02SEllis Hoag       if (!AnnotationFormName || !AnnotationFormValue)
37065d7fd02SEllis Hoag         continue;
37165d7fd02SEllis Hoag       auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
37265d7fd02SEllis Hoag       if (auto Err = AnnotationNameOrErr.takeError()) {
37365d7fd02SEllis Hoag         consumeError(std::move(Err));
37465d7fd02SEllis Hoag         continue;
37565d7fd02SEllis Hoag       }
37665d7fd02SEllis Hoag       StringRef AnnotationName = *AnnotationNameOrErr;
377b603237bSKazu Hirata       if (AnnotationName == InstrProfCorrelator::FunctionNameAttributeName) {
37865d7fd02SEllis Hoag         if (auto EC =
37965d7fd02SEllis Hoag                 AnnotationFormValue->getAsCString().moveInto(FunctionName))
38065d7fd02SEllis Hoag           consumeError(std::move(EC));
381b603237bSKazu Hirata       } else if (AnnotationName == InstrProfCorrelator::CFGHashAttributeName) {
38265d7fd02SEllis Hoag         CFGHash = AnnotationFormValue->getAsUnsignedConstant();
383b603237bSKazu Hirata       } else if (AnnotationName ==
384b603237bSKazu Hirata                  InstrProfCorrelator::NumCountersAttributeName) {
38565d7fd02SEllis Hoag         NumCounters = AnnotationFormValue->getAsUnsignedConstant();
38665d7fd02SEllis Hoag       }
38765d7fd02SEllis Hoag     }
38865d7fd02SEllis Hoag     if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) {
389d687caaeSEllis Hoag       if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
390d687caaeSEllis Hoag         WithColor::warning()
391d687caaeSEllis Hoag             << "Incomplete DIE for function " << FunctionName
392d687caaeSEllis Hoag             << ": CFGHash=" << CFGHash << "  CounterPtr=" << CounterPtr
393d687caaeSEllis Hoag             << "  NumCounters=" << NumCounters << "\n";
39465d7fd02SEllis Hoag         LLVM_DEBUG(Die.dump(dbgs()));
395d687caaeSEllis Hoag       }
39665d7fd02SEllis Hoag       return;
39765d7fd02SEllis Hoag     }
39865d7fd02SEllis Hoag     uint64_t CountersStart = this->Ctx->CountersSectionStart;
39965d7fd02SEllis Hoag     uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
40065d7fd02SEllis Hoag     if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) {
401d687caaeSEllis Hoag       if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
402d687caaeSEllis Hoag         WithColor::warning()
403d687caaeSEllis Hoag             << format("CounterPtr out of range for function %s: Actual=0x%x "
404d687caaeSEllis Hoag                       "Expected=[0x%x, 0x%x)\n",
405d687caaeSEllis Hoag                       *FunctionName, *CounterPtr, CountersStart, CountersEnd);
40665d7fd02SEllis Hoag         LLVM_DEBUG(Die.dump(dbgs()));
407d687caaeSEllis Hoag       }
40865d7fd02SEllis Hoag       return;
40965d7fd02SEllis Hoag     }
410d687caaeSEllis Hoag     if (!FunctionPtr && (UnlimitedWarnings || ++NumSuppressedWarnings < 1)) {
411d687caaeSEllis Hoag       WithColor::warning() << format("Could not find address of function %s\n",
412d687caaeSEllis Hoag                                      *FunctionName);
41365d7fd02SEllis Hoag       LLVM_DEBUG(Die.dump(dbgs()));
41465d7fd02SEllis Hoag     }
415ab3430f8SZequan Wu     // In debug info correlation mode, the CounterPtr is an absolute address of
416ab3430f8SZequan Wu     // the counter, but it's expected to be relative later when iterating Data.
41770fb7bb5SEllis Hoag     IntPtrT CounterOffset = *CounterPtr - CountersStart;
41870fb7bb5SEllis Hoag     if (Data) {
41970fb7bb5SEllis Hoag       InstrProfCorrelator::Probe P;
42070fb7bb5SEllis Hoag       P.FunctionName = *FunctionName;
42170fb7bb5SEllis Hoag       if (auto Name = FnDie.getName(DINameKind::LinkageName))
42270fb7bb5SEllis Hoag         P.LinkageName = Name;
42370fb7bb5SEllis Hoag       P.CFGHash = *CFGHash;
42470fb7bb5SEllis Hoag       P.CounterOffset = CounterOffset;
42570fb7bb5SEllis Hoag       P.NumCounters = *NumCounters;
42670fb7bb5SEllis Hoag       auto FilePath = FnDie.getDeclFile(
42770fb7bb5SEllis Hoag           DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath);
42870fb7bb5SEllis Hoag       if (!FilePath.empty())
42970fb7bb5SEllis Hoag         P.FilePath = FilePath;
43070fb7bb5SEllis Hoag       if (auto LineNumber = FnDie.getDeclLine())
43170fb7bb5SEllis Hoag         P.LineNumber = LineNumber;
43270fb7bb5SEllis Hoag       Data->Probes.push_back(P);
43370fb7bb5SEllis Hoag     } else {
434ab3430f8SZequan Wu       this->addDataProbe(IndexedInstrProf::ComputeHash(*FunctionName), *CFGHash,
435ab3430f8SZequan Wu                          CounterOffset, FunctionPtr.value_or(0), *NumCounters);
436ab3430f8SZequan Wu       this->NamesVec.push_back(*FunctionName);
43770fb7bb5SEllis Hoag     }
43865d7fd02SEllis Hoag   };
43965d7fd02SEllis Hoag   for (auto &CU : DICtx->normal_units())
44065d7fd02SEllis Hoag     for (const auto &Entry : CU->dies())
44165d7fd02SEllis Hoag       maybeAddProbe(DWARFDie(CU.get(), &Entry));
44265d7fd02SEllis Hoag   for (auto &CU : DICtx->dwo_units())
44365d7fd02SEllis Hoag     for (const auto &Entry : CU->dies())
44465d7fd02SEllis Hoag       maybeAddProbe(DWARFDie(CU.get(), &Entry));
445d687caaeSEllis Hoag 
446d687caaeSEllis Hoag   if (!UnlimitedWarnings && NumSuppressedWarnings > 0)
447d687caaeSEllis Hoag     WithColor::warning() << format("Suppressed %d additional warnings\n",
448d687caaeSEllis Hoag                                    NumSuppressedWarnings);
44965d7fd02SEllis Hoag }
4503c97c8b6SZequan Wu 
4513c97c8b6SZequan Wu template <class IntPtrT>
4523c97c8b6SZequan Wu Error DwarfInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
4533c97c8b6SZequan Wu   if (this->NamesVec.empty()) {
4543c97c8b6SZequan Wu     return make_error<InstrProfError>(
4553c97c8b6SZequan Wu         instrprof_error::unable_to_correlate_profile,
4563c97c8b6SZequan Wu         "could not find any profile name metadata in debug info");
4573c97c8b6SZequan Wu   }
4583c97c8b6SZequan Wu   auto Result =
4593c97c8b6SZequan Wu       collectGlobalObjectNameStrings(this->NamesVec,
4603c97c8b6SZequan Wu                                      /*doCompression=*/false, this->Names);
4613c97c8b6SZequan Wu   return Result;
4623c97c8b6SZequan Wu }
463ab3430f8SZequan Wu 
464ab3430f8SZequan Wu template <class IntPtrT>
465ab3430f8SZequan Wu void BinaryInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
466ab3430f8SZequan Wu     int MaxWarnings, InstrProfCorrelator::CorrelationData *CorrelateData) {
467ab3430f8SZequan Wu   using RawProfData = RawInstrProf::ProfileData<IntPtrT>;
468ab3430f8SZequan Wu   bool UnlimitedWarnings = (MaxWarnings == 0);
469ab3430f8SZequan Wu   // -N suppressed warnings means we can emit up to N (unsuppressed) warnings
470ab3430f8SZequan Wu   int NumSuppressedWarnings = -MaxWarnings;
471ab3430f8SZequan Wu 
472ab3430f8SZequan Wu   const RawProfData *DataStart = (const RawProfData *)this->Ctx->DataStart;
473ab3430f8SZequan Wu   const RawProfData *DataEnd = (const RawProfData *)this->Ctx->DataEnd;
474ab3430f8SZequan Wu   // We need to use < here because the last data record may have no padding.
475ab3430f8SZequan Wu   for (const RawProfData *I = DataStart; I < DataEnd; ++I) {
476ab3430f8SZequan Wu     uint64_t CounterPtr = this->template maybeSwap<IntPtrT>(I->CounterPtr);
477ab3430f8SZequan Wu     uint64_t CountersStart = this->Ctx->CountersSectionStart;
478ab3430f8SZequan Wu     uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
479ab3430f8SZequan Wu     if (CounterPtr < CountersStart || CounterPtr >= CountersEnd) {
480ab3430f8SZequan Wu       if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
481ab3430f8SZequan Wu         WithColor::warning()
482ab3430f8SZequan Wu             << format("CounterPtr out of range for function: Actual=0x%x "
483ab3430f8SZequan Wu                       "Expected=[0x%x, 0x%x) at data offset=0x%x\n",
484ab3430f8SZequan Wu                       CounterPtr, CountersStart, CountersEnd,
485ab3430f8SZequan Wu                       (I - DataStart) * sizeof(RawProfData));
486ab3430f8SZequan Wu       }
487ab3430f8SZequan Wu     }
488ab3430f8SZequan Wu     // In binary correlation mode, the CounterPtr is an absolute address of the
489ab3430f8SZequan Wu     // counter, but it's expected to be relative later when iterating Data.
490ab3430f8SZequan Wu     IntPtrT CounterOffset = CounterPtr - CountersStart;
491ab3430f8SZequan Wu     this->addDataProbe(I->NameRef, I->FuncHash, CounterOffset,
492ab3430f8SZequan Wu                        I->FunctionPointer, I->NumCounters);
493ab3430f8SZequan Wu   }
494ab3430f8SZequan Wu }
495ab3430f8SZequan Wu 
496ab3430f8SZequan Wu template <class IntPtrT>
497ab3430f8SZequan Wu Error BinaryInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
498ab3430f8SZequan Wu   if (this->Ctx->NameSize == 0) {
499ab3430f8SZequan Wu     return make_error<InstrProfError>(
500ab3430f8SZequan Wu         instrprof_error::unable_to_correlate_profile,
501ab3430f8SZequan Wu         "could not find any profile data metadata in object file");
502ab3430f8SZequan Wu   }
503ab3430f8SZequan Wu   this->Names.append(this->Ctx->NameStart, this->Ctx->NameSize);
504ab3430f8SZequan Wu   return Error::success();
505ab3430f8SZequan Wu }
506