llvm/bolt/lib/Core/BinaryFunction.cpp

//===- bolt/Core/BinaryFunction.cpp - Low-level function ------------------===//
//
// 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 implements the BinaryFunction class.
//
//===----------------------------------------------------------------------===//

#include "bolt/Core/BinaryFunction.h"
#include "bolt/Core/BinaryBasicBlock.h"
#include "bolt/Core/DynoStats.h"
#include "bolt/Core/HashUtilities.h"
#include "bolt/Core/MCPlusBuilder.h"
#include "bolt/Utils/NameResolver.h"
#include "bolt/Utils/NameShortener.h"
#include "bolt/Utils/Utils.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/GenericDomTreeConstruction.h"
#include "llvm/Support/GenericLoopInfoImpl.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/xxhash.h"
#include <functional>
#include <limits>
#include <numeric>
#include <stack>
#include <string>

#define DEBUG_TYPE

usingnamespacellvm;
usingnamespacebolt;

namespace opts {

extern cl::OptionCategory BoltCategory;
extern cl::OptionCategory BoltOptCategory;

extern cl::opt<bool> EnableBAT;
extern cl::opt<bool> Instrument;
extern cl::opt<bool> StrictMode;
extern cl::opt<bool> UpdateDebugSections;
extern cl::opt<unsigned> Verbosity;

extern bool processAllFunctions();

cl::opt<bool> CheckEncoding(
    "check-encoding",
    cl::desc("perform verification of LLVM instruction encoding/decoding. "
             "Every instruction in the input is decoded and re-encoded. "
             "If the resulting bytes do not match the input, a warning message "
             "is printed."),
    cl::Hidden, cl::cat(BoltCategory));

static cl::opt<bool> DotToolTipCode(
    "dot-tooltip-code",
    cl::desc("add basic block instructions as tool tips on nodes"), cl::Hidden,
    cl::cat(BoltCategory));

cl::opt<JumpTableSupportLevel>
JumpTables("jump-tables",
  cl::desc("jump tables support (default=basic)"),
  cl::init(JTS_BASIC),
  cl::values(
      clEnumValN(JTS_NONE, "none",
                 "do not optimize functions with jump tables"),
      clEnumValN(JTS_BASIC, "basic",
                 "optimize functions with jump tables"),
      clEnumValN(JTS_MOVE, "move",
                 "move jump tables to a separate section"),
      clEnumValN(JTS_SPLIT, "split",
                 "split jump tables section into hot and cold based on "
                 "function execution frequency"),
      clEnumValN(JTS_AGGRESSIVE, "aggressive",
                 "aggressively split jump tables section based on usage "
                 "of the tables")),
  cl::ZeroOrMore,
  cl::cat(BoltOptCategory));

static cl::opt<bool> NoScan(
    "no-scan",
    cl::desc(
        "do not scan cold functions for external references (may result in "
        "slower binary)"),
    cl::Hidden, cl::cat(BoltOptCategory));

cl::opt<bool>
    PreserveBlocksAlignment("preserve-blocks-alignment",
                            cl::desc("try to preserve basic block alignment"),
                            cl::cat(BoltOptCategory));

static cl::opt<bool> PrintOutputAddressRange(
    "print-output-address-range",
    cl::desc(
        "print output address range for each basic block in the function when"
        "BinaryFunction::print is called"),
    cl::Hidden, cl::cat(BoltOptCategory));

cl::opt<bool>
PrintDynoStats("dyno-stats",
  cl::desc("print execution info based on profile"),
  cl::cat(BoltCategory));

static cl::opt<bool>
PrintDynoStatsOnly("print-dyno-stats-only",
  cl::desc("while printing functions output dyno-stats and skip instructions"),
  cl::init(false),
  cl::Hidden,
  cl::cat(BoltCategory));

static cl::list<std::string>
PrintOnly("print-only",
  cl::CommaSeparated,
  cl::desc("list of functions to print"),
  cl::value_desc("func1,func2,func3,..."),
  cl::Hidden,
  cl::cat(BoltCategory));

cl::opt<bool>
    TimeBuild("time-build",
              cl::desc("print time spent constructing binary functions"),
              cl::Hidden, cl::cat(BoltCategory));

cl::opt<bool>
TrapOnAVX512("trap-avx512",
  cl::desc("in relocation mode trap upon entry to any function that uses "
            "AVX-512 instructions"),
  cl::init(false),
  cl::ZeroOrMore,
  cl::Hidden,
  cl::cat(BoltCategory));

bool shouldPrint(const BinaryFunction &Function) {}

} // namespace opts

namespace llvm {
namespace bolt {

template <typename R> static bool emptyRange(const R &Range) {}

/// Gets debug line information for the instruction located at the given
/// address in the original binary. The SMLoc's pointer is used
/// to point to this information, which is represented by a
/// DebugLineTableRowRef. The returned pointer is null if no debug line
/// information for this instruction was found.
static SMLoc findDebugLineInformationForInstructionAt(
    uint64_t Address, DWARFUnit *Unit,
    const DWARFDebugLine::LineTable *LineTable) {}

static std::string buildSectionName(StringRef Prefix, StringRef Name,
                                    const BinaryContext &BC) {}

static raw_ostream &operator<<(raw_ostream &OS,
                               const BinaryFunction::State State) {}

std::string BinaryFunction::buildCodeSectionName(StringRef Name,
                                                 const BinaryContext &BC) {}

std::string BinaryFunction::buildColdCodeSectionName(StringRef Name,
                                                     const BinaryContext &BC) {}

uint64_t BinaryFunction::Count =;

std::optional<StringRef>
BinaryFunction::hasNameRegex(const StringRef Name) const {}

std::optional<StringRef>
BinaryFunction::hasRestoredNameRegex(const StringRef Name) const {}

std::string BinaryFunction::getDemangledName() const {}

BinaryBasicBlock *
BinaryFunction::getBasicBlockContainingOffset(uint64_t Offset) {}

void BinaryFunction::markUnreachableBlocks() {}

// Any unnecessary fallthrough jumps revealed after calling eraseInvalidBBs
// will be cleaned up by fixBranches().
std::pair<unsigned, uint64_t>
BinaryFunction::eraseInvalidBBs(const MCCodeEmitter *Emitter) {}

bool BinaryFunction::isForwardCall(const MCSymbol *CalleeSymbol) const {}

void BinaryFunction::dump() const {}

void BinaryFunction::print(raw_ostream &OS, std::string Annotation) {}

void BinaryFunction::printRelocations(raw_ostream &OS, uint64_t Offset,
                                      uint64_t Size) const {}

static std::string mutateDWARFExpressionTargetReg(const MCCFIInstruction &Instr,
                                                  MCPhysReg NewReg) {}

void BinaryFunction::mutateCFIRegisterFor(const MCInst &Instr,
                                          MCPhysReg NewReg) {}

const MCCFIInstruction *BinaryFunction::mutateCFIOffsetFor(const MCInst &Instr,
                                                           int64_t NewOffset) {}

IndirectBranchType
BinaryFunction::processIndirectBranch(MCInst &Instruction, unsigned Size,
                                      uint64_t Offset,
                                      uint64_t &TargetAddress) {}

MCSymbol *BinaryFunction::getOrCreateLocalLabel(uint64_t Address,
                                                bool CreatePastEnd) {}

ErrorOr<ArrayRef<uint8_t>> BinaryFunction::getData() const {}

size_t BinaryFunction::getSizeOfDataInCodeAt(uint64_t Offset) const {}

bool BinaryFunction::isZeroPaddingAt(uint64_t Offset) const {}

Error BinaryFunction::handlePCRelOperand(MCInst &Instruction, uint64_t Address,
                                         uint64_t Size) {}

MCSymbol *BinaryFunction::handleExternalReference(MCInst &Instruction,
                                                  uint64_t Size,
                                                  uint64_t Offset,
                                                  uint64_t TargetAddress,
                                                  bool &IsCall) {}

void BinaryFunction::handleIndirectBranch(MCInst &Instruction, uint64_t Size,
                                          uint64_t Offset) {}

void BinaryFunction::handleAArch64IndirectCall(MCInst &Instruction,
                                               const uint64_t Offset) {}

std::optional<MCInst>
BinaryFunction::disassembleInstructionAtOffset(uint64_t Offset) const {}

Error BinaryFunction::disassemble() {}

MCSymbol *BinaryFunction::registerBranch(uint64_t Src, uint64_t Dst) {}

bool BinaryFunction::scanExternalRefs() {}

void BinaryFunction::postProcessEntryPoints() {}

void BinaryFunction::postProcessJumpTables() {}

bool BinaryFunction::validateExternallyReferencedOffsets() {}

bool BinaryFunction::postProcessIndirectBranches(
    MCPlusBuilder::AllocatorIdTy AllocId) {}

void BinaryFunction::recomputeLandingPads() {}

Error BinaryFunction::buildCFG(MCPlusBuilder::AllocatorIdTy AllocatorId) {}

void BinaryFunction::postProcessCFG() {}

void BinaryFunction::removeTagsFromProfile() {}

void BinaryFunction::removeConditionalTailCalls() {}

uint64_t BinaryFunction::getFunctionScore() const {}

void BinaryFunction::annotateCFIState() {}

namespace {

/// Our full interpretation of a DWARF CFI machine state at a given point
struct CFISnapshot {};

/// A CFI snapshot with the capability of checking if incremental additions to
/// it are redundant. This is used to ensure we do not emit two CFI instructions
/// back-to-back that are doing the same state change, or to avoid emitting a
/// CFI at all when the state at that point would not be modified after that CFI
struct CFISnapshotDiff : public CFISnapshot {};

} // end anonymous namespace

bool BinaryFunction::replayCFIInstrs(int32_t FromState, int32_t ToState,
                                     BinaryBasicBlock *InBB,
                                     BinaryBasicBlock::iterator InsertIt) {}

SmallVector<int32_t, 4>
BinaryFunction::unwindCFIState(int32_t FromState, int32_t ToState,
                               BinaryBasicBlock *InBB,
                               BinaryBasicBlock::iterator &InsertIt) {}

void BinaryFunction::normalizeCFIState() {}

bool BinaryFunction::finalizeCFIState() {}

bool BinaryFunction::requiresAddressTranslation() const {}

bool BinaryFunction::requiresAddressMap() const {}

uint64_t BinaryFunction::getInstructionCount() const {}

void BinaryFunction::clearDisasmState() {}

void BinaryFunction::setTrapOnEntry() {}

void BinaryFunction::setIgnored() {}

void BinaryFunction::duplicateConstantIslands() {}

#ifndef MAX_PATH
#define MAX_PATH
#endif

static std::string constructFilename(std::string Filename,
                                     std::string Annotation,
                                     std::string Suffix) {}

static std::string formatEscapes(const std::string &Str) {}

void BinaryFunction::dumpGraph(raw_ostream &OS) const {}

void BinaryFunction::viewGraph() const {}

void BinaryFunction::dumpGraphForPass(std::string Annotation) const {}

void BinaryFunction::dumpGraphToFile(std::string Filename) const {}

bool BinaryFunction::validateCFG() const {}

void BinaryFunction::fixBranches() {}

void BinaryFunction::propagateGnuArgsSizeInfo(
    MCPlusBuilder::AllocatorIdTy AllocId) {}

void BinaryFunction::postProcessBranches() {}

MCSymbol *BinaryFunction::addEntryPointAtOffset(uint64_t Offset) {}

MCSymbol *BinaryFunction::addEntryPoint(const BinaryBasicBlock &BB) {}

MCSymbol *BinaryFunction::getSymbolForEntryID(uint64_t EntryID) {}

uint64_t BinaryFunction::getEntryIDForSymbol(const MCSymbol *Symbol) const {}

bool BinaryFunction::forEachEntryPoint(EntryPointCallbackTy Callback) const {}

BinaryFunction::BasicBlockListType BinaryFunction::dfs() const {}

size_t BinaryFunction::computeHash(bool UseDFS, HashFunction HashFunction,
                                   OperandHashFuncTy OperandHashFunc) const {}

void BinaryFunction::insertBasicBlocks(
    BinaryBasicBlock *Start,
    std::vector<std::unique_ptr<BinaryBasicBlock>> &&NewBBs,
    const bool UpdateLayout, const bool UpdateCFIState,
    const bool RecomputeLandingPads) {}

BinaryFunction::iterator BinaryFunction::insertBasicBlocks(
    BinaryFunction::iterator StartBB,
    std::vector<std::unique_ptr<BinaryBasicBlock>> &&NewBBs,
    const bool UpdateLayout, const bool UpdateCFIState,
    const bool RecomputeLandingPads) {}

void BinaryFunction::updateBBIndices(const unsigned StartIndex) {}

void BinaryFunction::updateCFIState(BinaryBasicBlock *Start,
                                    const unsigned NumNewBlocks) {}

void BinaryFunction::updateLayout(BinaryBasicBlock *Start,
                                  const unsigned NumNewBlocks) {}

bool BinaryFunction::checkForAmbiguousJumpTables() {}

void BinaryFunction::disambiguateJumpTables(
    MCPlusBuilder::AllocatorIdTy AllocId) {}

bool BinaryFunction::replaceJumpTableEntryIn(BinaryBasicBlock *BB,
                                             BinaryBasicBlock *OldDest,
                                             BinaryBasicBlock *NewDest) {}

BinaryBasicBlock *BinaryFunction::splitEdge(BinaryBasicBlock *From,
                                            BinaryBasicBlock *To) {}

void BinaryFunction::deleteConservativeEdges() {}

bool BinaryFunction::isSymbolValidInScope(const SymbolRef &Symbol,
                                          uint64_t SymbolSize) const {}

void BinaryFunction::adjustExecutionCount(uint64_t Count) {}

BinaryFunction::~BinaryFunction() {}

void BinaryFunction::constructDomTree() {}

void BinaryFunction::calculateLoopInfo() {}

void BinaryFunction::updateOutputValues(const BOLTLinker &Linker) {}

DebugAddressRangesVector BinaryFunction::getOutputAddressRanges() const {}

uint64_t BinaryFunction::translateInputToOutputAddress(uint64_t Address) const {}

DebugAddressRangesVector
BinaryFunction::translateInputToOutputRange(DebugAddressRange InRange) const {}

MCInst *BinaryFunction::getInstructionAtOffset(uint64_t Offset) {}

MCInst *BinaryFunction::getInstructionContainingOffset(uint64_t Offset) {}

void BinaryFunction::printLoopInfo(raw_ostream &OS) const {}

bool BinaryFunction::isAArch64Veneer() const {}

void BinaryFunction::addRelocation(uint64_t Address, MCSymbol *Symbol,
                                   uint64_t RelType, uint64_t Addend,
                                   uint64_t Value) {}

} // namespace bolt
} // namespace llvm