//===- InstrProfCorrelator.h ------------------------------------*- C++ -*-===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
// This file defines InstrProfCorrelator used to generate PGO profiles from
 
// raw profile data and debug info.
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
 
#define LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
 
 
 
#include "llvm/ADT/DenseSet.h"
 
#include "llvm/ProfileData/InstrProf.h"
 
#include "llvm/Support/Error.h"
 
#include "llvm/Support/MemoryBuffer.h"
 
#include "llvm/Support/YAMLTraits.h"
 
#include <optional>
 
#include <vector>
 
 
 
namespace llvm {
 
class DWARFContext;
 
class DWARFDie;
 
namespace object {
 
class ObjectFile;
 
}
 
 
 
/// InstrProfCorrelator - A base class used to create raw instrumentation data
 
/// to their functions.
 
class InstrProfCorrelator {
 
public:
 
  static llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
 
  get(StringRef DebugInfoFilename);
 
 
 
  /// Construct a ProfileData vector used to correlate raw instrumentation data
 
  /// to their functions.
 
  virtual Error correlateProfileData() = 0;
 
 
 
  /// Process debug info and dump the correlation data.
 
  virtual Error dumpYaml(raw_ostream &OS) = 0;
 
 
 
  /// Return the number of ProfileData elements.
 
  std::optional<size_t> getDataSize() const;
 
 
 
  /// Return a pointer to the names string that this class constructs.
 
  const char *getNamesPointer() const { return Names.c_str(); }
 
 
 
  /// Return the number of bytes in the names string.
 
  size_t getNamesSize() const { return Names.size(); }
 
 
 
  /// Return the size of the counters section in bytes.
 
  uint64_t getCountersSectionSize() const {
 
    return Ctx->CountersSectionEnd - Ctx->CountersSectionStart;
 
  }
 
 
 
  static const char *FunctionNameAttributeName;
 
  static const char *CFGHashAttributeName;
 
  static const char *NumCountersAttributeName;
 
 
 
  enum InstrProfCorrelatorKind { CK_32Bit, CK_64Bit };
 
  InstrProfCorrelatorKind getKind() const { return Kind; }
 
  virtual ~InstrProfCorrelator() = default;
 
 
 
protected:
 
  struct Context {
 
    static llvm::Expected<std::unique_ptr<Context>>
 
    get(std::unique_ptr<MemoryBuffer> Buffer, const object::ObjectFile &Obj);
 
    std::unique_ptr<MemoryBuffer> Buffer;
 
    /// The address range of the __llvm_prf_cnts section.
 
    uint64_t CountersSectionStart;
 
    uint64_t CountersSectionEnd;
 
    /// True if target and host have different endian orders.
 
    bool ShouldSwapBytes;
 
  };
 
  const std::unique_ptr<Context> Ctx;
 
 
 
  InstrProfCorrelator(InstrProfCorrelatorKind K, std::unique_ptr<Context> Ctx)
 
      : Ctx(std::move(Ctx)), Kind(K) {}
 
 
 
  std::string Names;
 
  std::vector<std::string> NamesVec;
 
 
 
  struct Probe {
 
    std::string FunctionName;
 
    std::optional<std::string> LinkageName;
 
    yaml::Hex64 CFGHash;
 
    yaml::Hex64 CounterOffset;
 
    uint32_t NumCounters;
 
    std::optional<std::string> FilePath;
 
    std::optional<int> LineNumber;
 
  };
 
 
 
  struct CorrelationData {
 
    std::vector<Probe> Probes;
 
  };
 
 
 
  friend struct yaml::MappingTraits<Probe>;
 
  friend struct yaml::SequenceElementTraits<Probe>;
 
  friend struct yaml::MappingTraits<CorrelationData>;
 
 
 
private:
 
  static llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
 
  get(std::unique_ptr<MemoryBuffer> Buffer);
 
 
 
  const InstrProfCorrelatorKind Kind;
 
};
 
 
 
/// InstrProfCorrelatorImpl - A child of InstrProfCorrelator with a template
 
/// pointer type so that the ProfileData vector can be materialized.
 
template <class IntPtrT>
 
class InstrProfCorrelatorImpl : public InstrProfCorrelator {
 
public:
 
  InstrProfCorrelatorImpl(std::unique_ptr<InstrProfCorrelator::Context> Ctx);
 
  static bool classof(const InstrProfCorrelator *C);
 
 
 
  /// Return a pointer to the underlying ProfileData vector that this class
 
  /// constructs.
 
  const RawInstrProf::ProfileData<IntPtrT> *getDataPointer() const {
 
    return Data.empty() ? nullptr : Data.data();
 
  }
 
 
 
  /// Return the number of ProfileData elements.
 
  size_t getDataSize() const { return Data.size(); }
 
 
 
  static llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>>
 
  get(std::unique_ptr<InstrProfCorrelator::Context> Ctx,
 
      const object::ObjectFile &Obj);
 
 
 
protected:
 
  std::vector<RawInstrProf::ProfileData<IntPtrT>> Data;
 
 
 
  Error correlateProfileData() override;
 
  virtual void correlateProfileDataImpl(
 
      InstrProfCorrelator::CorrelationData *Data = nullptr) = 0;
 
 
 
  Error dumpYaml(raw_ostream &OS) override;
 
 
 
  void addProbe(StringRef FunctionName, uint64_t CFGHash, IntPtrT CounterOffset,
 
                IntPtrT FunctionPtr, uint32_t NumCounters);
 
 
 
private:
 
  InstrProfCorrelatorImpl(InstrProfCorrelatorKind Kind,
 
                          std::unique_ptr<InstrProfCorrelator::Context> Ctx)
 
      : InstrProfCorrelator(Kind, std::move(Ctx)){};
 
  llvm::DenseSet<IntPtrT> CounterOffsets;
 
 
 
  // Byte-swap the value if necessary.
 
  template <class T> T maybeSwap(T Value) const {
 
    return Ctx->ShouldSwapBytes ? sys::getSwappedBytes(Value) : Value;
 
  }
 
};
 
 
 
/// DwarfInstrProfCorrelator - A child of InstrProfCorrelatorImpl that takes
 
/// DWARF debug info as input to correlate profiles.
 
template <class IntPtrT>
 
class DwarfInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> {
 
public:
 
  DwarfInstrProfCorrelator(std::unique_ptr<DWARFContext> DICtx,
 
                           std::unique_ptr<InstrProfCorrelator::Context> Ctx)
 
      : InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx)),
 
        DICtx(std::move(DICtx)) {}
 
 
 
private:
 
  std::unique_ptr<DWARFContext> DICtx;
 
 
 
  /// Return the address of the object that the provided DIE symbolizes.
 
  std::optional<uint64_t> getLocation(const DWARFDie &Die) const;
 
 
 
  /// Returns true if the provided DIE symbolizes an instrumentation probe
 
  /// symbol.
 
  static bool isDIEOfProbe(const DWARFDie &Die);
 
 
 
  /// Iterate over DWARF DIEs to find those that symbolize instrumentation
 
  /// probes and construct the ProfileData vector and Names string.
 
  ///
 
  /// Here is some example DWARF for an instrumentation probe we are looking
 
  /// for:
 
  /// \code
 
  ///   DW_TAG_subprogram
 
  ///   DW_AT_low_pc    (0x0000000000000000)
 
  ///   DW_AT_high_pc   (0x0000000000000014)
 
  ///   DW_AT_name      ("foo")
 
  ///     DW_TAG_variable
 
  ///       DW_AT_name  ("__profc_foo")
 
  ///       DW_AT_location      (DW_OP_addr 0x0)
 
  ///       DW_TAG_LLVM_annotation
 
  ///         DW_AT_name        ("Function Name")
 
  ///         DW_AT_const_value ("foo")
 
  ///       DW_TAG_LLVM_annotation
 
  ///         DW_AT_name        ("CFG Hash")
 
  ///         DW_AT_const_value (12345678)
 
  ///       DW_TAG_LLVM_annotation
 
  ///         DW_AT_name        ("Num Counters")
 
  ///         DW_AT_const_value (2)
 
  ///       NULL
 
  ///     NULL
 
  /// \endcode
 
  void correlateProfileDataImpl(
 
      InstrProfCorrelator::CorrelationData *Data = nullptr) override;
 
};
 
 
 
} // end namespace llvm
 
 
 
#endif // LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H