23#define DEBUG_TYPE "correlator"
33 return make_error<InstrProfError>(
34 instrprof_error::unable_to_correlate_profile,
35 "could not find counter section (" INSTR_PROF_CNTS_SECT_NAME
")");
42 "Coverage Function Name";
48 if (
auto Err = CountersSection.takeError())
49 return std::move(Err);
50 auto C = std::make_unique<Context>();
52 C->CountersSectionStart = CountersSection->getAddress();
53 C->CountersSectionEnd =
C->CountersSectionStart + CountersSection->getSize();
60 auto DsymObjectsOrErr =
62 if (
auto Err = DsymObjectsOrErr.takeError())
63 return std::move(Err);
64 if (!DsymObjectsOrErr->empty()) {
67 if (DsymObjectsOrErr->size() > 1)
68 return make_error<InstrProfError>(
70 "using multiple objects is not yet supported");
71 DebugInfoFilename = *DsymObjectsOrErr->
begin();
75 if (
auto Err = BufferOrErr.takeError())
76 return std::move(Err);
78 return get(std::move(*BufferOrErr));
84 if (
auto Err = BinOrErr.takeError())
85 return std::move(Err);
87 if (
auto *Obj = dyn_cast<object::ObjectFile>(BinOrErr->get())) {
89 if (
auto Err = CtxOrErr.takeError())
90 return std::move(Err);
91 auto T = Obj->makeTriple();
97 return make_error<InstrProfError>(
103 return C->getDataSize();
105 return C->getDataSize();
114 std::unique_ptr<InstrProfCorrelator::Context> Ctx)
119 std::unique_ptr<InstrProfCorrelator::Context> Ctx)
124 return C->getKind() == InstrProfCorrelatorKind::CK_32Bit;
128 return C->getKind() == InstrProfCorrelatorKind::CK_64Bit;
133template <
class IntPtrT>
136 std::unique_ptr<InstrProfCorrelator::Context> Ctx,
140 return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>(std::move(DICtx),
143 return make_error<InstrProfError>(
144 instrprof_error::unable_to_correlate_profile,
145 "unsupported debug info format (only DWARF is supported)");
148template <
class IntPtrT>
150 assert(
Data.empty() && Names.empty() && NamesVec.empty());
151 correlateProfileDataImpl(MaxWarnings);
152 if (
Data.empty() || NamesVec.empty())
153 return make_error<InstrProfError>(
154 instrprof_error::unable_to_correlate_profile,
155 "could not find any profile metadata in debug info");
158 CounterOffsets.clear();
166 io.mapRequired(
"Probes",
Data.Probes);
172 io.mapRequired(
"Function Name",
P.FunctionName);
173 io.mapOptional(
"Linkage Name",
P.LinkageName);
174 io.mapRequired(
"CFG Hash",
P.CFGHash);
175 io.mapRequired(
"Counter Offset",
P.CounterOffset);
176 io.mapRequired(
"Num Counters",
P.NumCounters);
177 io.mapOptional(
"File",
P.FilePath);
178 io.mapOptional(
"Line",
P.LineNumber);
183 static const bool flow =
false;
186template <
class IntPtrT>
190 correlateProfileDataImpl(MaxWarnings, &
Data);
191 if (
Data.Probes.empty())
192 return make_error<InstrProfError>(
193 instrprof_error::unable_to_correlate_profile,
194 "could not find any profile metadata in debug info");
195 yaml::Output YamlOS(
OS);
200template <
class IntPtrT>
207 if (!CounterOffsets.insert(CounterOffset).second)
211 maybeSwap<uint64_t>(CFGHash),
214 maybeSwap<IntPtrT>(CounterOffset),
215 maybeSwap<IntPtrT>(FunctionPtr),
217 maybeSwap<IntPtrT>(0),
218 maybeSwap<uint32_t>(NumCounters),
219 {maybeSwap<uint16_t>(0), maybeSwap<uint16_t>(0)},
221 NamesVec.push_back(FunctionName.
str());
224template <
class IntPtrT>
225std::optional<uint64_t>
227 auto Locations = Die.
getLocations(dwarf::DW_AT_location);
234 for (
auto &Location : *Locations) {
237 for (
auto &
Op : Expr) {
240 }
else if (
Op.
getCode() == dwarf::DW_OP_addrx) {
242 if (
auto SA = DU.getAddrOffsetSectionItem(
Index))
250template <
class IntPtrT>
255 if (Die.
getTag() != dwarf::DW_TAG_variable)
257 if (!ParentDie.isSubprogramDIE())
261 if (
const char *
Name = Die.
getName(DINameKind::ShortName))
266template <
class IntPtrT>
269 bool UnlimitedWarnings = (MaxWarnings == 0);
271 int NumSuppressedWarnings = -MaxWarnings;
272 auto maybeAddProbe = [&](
DWARFDie Die) {
273 if (!isDIEOfProbe(Die))
275 std::optional<const char *> FunctionName;
276 std::optional<uint64_t> CFGHash;
277 std::optional<uint64_t> CounterPtr =
getLocation(Die);
280 std::optional<uint64_t> NumCounters;
282 if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
284 auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
285 auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
286 if (!AnnotationFormName || !AnnotationFormValue)
288 auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
289 if (
auto Err = AnnotationNameOrErr.takeError()) {
293 StringRef AnnotationName = *AnnotationNameOrErr;
297 AnnotationFormValue->getAsCString().moveInto(FunctionName))
299 }
else if (AnnotationName.
compare(
301 CFGHash = AnnotationFormValue->getAsUnsignedConstant();
302 }
else if (AnnotationName.
compare(
304 NumCounters = AnnotationFormValue->getAsUnsignedConstant();
307 if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) {
308 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
310 <<
"Incomplete DIE for function " << FunctionName
311 <<
": CFGHash=" << CFGHash <<
" CounterPtr=" << CounterPtr
312 <<
" NumCounters=" << NumCounters <<
"\n";
317 uint64_t CountersStart = this->Ctx->CountersSectionStart;
318 uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
319 if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) {
320 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
322 <<
format(
"CounterPtr out of range for function %s: Actual=0x%x "
323 "Expected=[0x%x, 0x%x)\n",
324 *FunctionName, *CounterPtr, CountersStart, CountersEnd);
329 if (!FunctionPtr && (UnlimitedWarnings || ++NumSuppressedWarnings < 1)) {
334 IntPtrT CounterOffset = *CounterPtr - CountersStart;
337 P.FunctionName = *FunctionName;
338 if (
auto Name = FnDie.getName(DINameKind::LinkageName))
339 P.LinkageName =
Name;
340 P.CFGHash = *CFGHash;
341 P.CounterOffset = CounterOffset;
342 P.NumCounters = *NumCounters;
343 auto FilePath = FnDie.getDeclFile(
344 DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath);
345 if (!FilePath.empty())
346 P.FilePath = FilePath;
347 if (
auto LineNumber = FnDie.getDeclLine())
348 P.LineNumber = LineNumber;
349 Data->Probes.push_back(
P);
351 this->addProbe(*FunctionName, *CFGHash, CounterOffset,
352 FunctionPtr.value_or(0), *NumCounters);
355 for (
auto &
CU : DICtx->normal_units())
356 for (
const auto &Entry :
CU->dies())
358 for (
auto &
CU : DICtx->dwo_units())
359 for (
const auto &Entry :
CU->dies())
362 if (!UnlimitedWarnings && NumSuppressedWarnings > 0)
364 NumSuppressedWarnings);
367template <
class IntPtrT>
370 bool UnlimitedWarnings = (MaxWarnings == 0);
372 int NumSuppressedWarnings = -MaxWarnings;
373 std::vector<std::string> UnusedFuncNames;
374 auto IsDIEOfCovName = [](
const DWARFDie &Die) {
378 if (Die.
getTag() != dwarf::DW_TAG_variable)
380 if (ParentDie.getParent().isValid())
384 if (
const char *
Name = Die.
getName(DINameKind::ShortName))
388 auto MaybeAddCovFuncName = [&](
DWARFDie Die) {
389 if (!IsDIEOfCovName(Die))
392 if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
394 auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
395 auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
396 if (!AnnotationFormName || !AnnotationFormValue)
398 auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
399 if (
auto Err = AnnotationNameOrErr.takeError()) {
403 std::optional<const char *> FunctionName;
404 StringRef AnnotationName = *AnnotationNameOrErr;
408 AnnotationFormValue->getAsCString().moveInto(FunctionName))
412 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
414 "Missing coverage function name value at DIE 0x%08" PRIx64,
419 UnusedFuncNames.push_back(*FunctionName);
422 for (
auto &
CU : DICtx->normal_units())
423 for (
const auto &Entry :
CU->dies())
424 MaybeAddCovFuncName(
DWARFDie(
CU.get(), &Entry));
425 for (
auto &
CU : DICtx->dwo_units())
426 for (
const auto &Entry :
CU->dies())
427 MaybeAddCovFuncName(
DWARFDie(
CU.get(), &Entry));
429 if (!UnlimitedWarnings && NumSuppressedWarnings > 0)
431 NumSuppressedWarnings);
432 if (!UnusedFuncNames.empty()) {
434 UnusedFuncNames,
false, this->CovUnusedFuncNames);
Expected< object::SectionRef > getCountersSection(const object::ObjectFile &Obj)
Get the __llvm_prf_cnts section.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static MemoryLocation getLocation(Instruction *I)
static std::unique_ptr< DWARFContext > create(const object::ObjectFile &Obj, ProcessDebugRelocations RelocAction=ProcessDebugRelocations::Process, const LoadedObjectInfo *L=nullptr, std::string DWPName="", std::function< void(Error)> RecoverableErrorHandler=WithColor::defaultErrorHandler, std::function< void(Error)> WarningHandler=WithColor::defaultWarningHandler, bool ThreadSafe=false)
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
iterator_range< iterator > children() const
DWARFDie getParent() const
Get the parent of this DIE object.
DWARFUnit * getDwarfUnit() const
const char * getName(DINameKind Kind) const
Return the DIE name resolving DW_AT_specification or DW_AT_abstract_origin references if necessary.
dwarf::Tag getTag() const
Expected< DWARFLocationExpressionsVector > getLocations(dwarf::Attribute Attr) const
bool isNULL() const
Returns true for a valid DIE that terminates a sibling chain.
void dump(raw_ostream &OS, unsigned indent=0, DIDumpOptions DumpOpts=DIDumpOptions()) const
Dump the DIE and all of its attributes to the supplied stream.
This class represents an Operation in the Expression.
uint64_t getRawOperand(unsigned Idx) const
uint8_t getAddressByteSize() const
DwarfInstrProfCorrelator - A child of InstrProfCorrelatorImpl that takes DWARF debug info as input to...
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
InstrProfCorrelatorImpl - A child of InstrProfCorrelator with a template pointer type so that the Pro...
Error correlateProfileData(int MaxWarnings) override
Construct a ProfileData vector used to correlate raw instrumentation data to their functions.
static bool classof(const InstrProfCorrelator *C)
InstrProfCorrelatorImpl(std::unique_ptr< InstrProfCorrelator::Context > Ctx)
void addProbe(StringRef FunctionName, uint64_t CFGHash, IntPtrT CounterOffset, IntPtrT FunctionPtr, uint32_t NumCounters)
Error dumpYaml(int MaxWarnings, raw_ostream &OS) override
Process debug info and dump the correlation data.
static llvm::Expected< std::unique_ptr< InstrProfCorrelatorImpl< IntPtrT > > > get(std::unique_ptr< InstrProfCorrelator::Context > Ctx, const object::ObjectFile &Obj)
InstrProfCorrelator - A base class used to create raw instrumentation data to their functions.
static const char * FunctionNameAttributeName
static const char * CFGHashAttributeName
static llvm::Expected< std::unique_ptr< InstrProfCorrelator > > get(StringRef DebugInfoFilename)
static const char * CovFunctionNameAttributeName
static const char * NumCountersAttributeName
std::optional< size_t > getDataSize() const
Return the number of ProfileData elements.
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
StringRef - Represent a constant reference to a string, i.e.
std::string str() const
str - Get the contents as an std::string.
bool startswith(StringRef Prefix) const
int compare(StringRef RHS) const
compare - Compare two strings; the result is negative, zero, or positive if this string is lexicograp...
static raw_ostream & warning()
Convenience method for printing "warning: " to stderr.
bool isLittleEndian() const
static Expected< std::vector< std::string > > findDsymObjectMembers(StringRef Path)
If the input path is a .dSYM bundle (as created by the dsymutil tool), return the paths to the object...
This class is the base class for all object file types.
section_iterator_range sections() const
This class implements an extremely fast bulk output stream that can only output to a stream.
@ C
The default llvm calling convention, compatible with C.
uint64_t ComputeHash(StringRef K)
std::optional< uint64_t > toAddress(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an address.
Expected< std::unique_ptr< Binary > > createBinary(MemoryBufferRef Source, LLVMContext *Context=nullptr, bool InitContent=true)
Create a Binary from Source, autodetecting the file type.
static const bool IsLittleEndianHost
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
StringRef getCoverageUnusedNamesVarName()
Return the name of the internal variable recording the array of PGO name vars referenced by the cover...
StringRef getInstrProfCountersVarPrefix()
Return the name prefix of profile counter variables.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
@ unable_to_correlate_profile
Expected< T > errorOrToExpected(ErrorOr< T > &&EO)
Convert an ErrorOr<T> to an Expected<T>.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Error collectPGOFuncNameStrings(ArrayRef< std::string > NameStrs, bool doCompression, std::string &Result)
Given a vector of strings (function PGO names) NameStrs, the method generates a combined string Resul...
void consumeError(Error Err)
Consume a Error without doing anything.
Implement std::hash so that hash_code can be used in STL containers.
static llvm::Expected< std::unique_ptr< Context > > get(std::unique_ptr< MemoryBuffer > Buffer, const object::ObjectFile &Obj)
std::unique_ptr< MemoryBuffer > Buffer
static void mapping(yaml::IO &io, InstrProfCorrelator::CorrelationData &Data)
static void mapping(yaml::IO &io, InstrProfCorrelator::Probe &P)