Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions llvm/include/llvm/CodeGen/MachineBlockHashInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//===- llvm/CodeGen/MachineBlockHashInfo.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
//
//===----------------------------------------------------------------------===//
//
// Compute the hashes of basic blocks.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CODEGEN_MACHINEBLOCKHASHINFO_H
#define LLVM_CODEGEN_MACHINEBLOCKHASHINFO_H

#include "llvm/CodeGen/MachineFunctionPass.h"

namespace llvm {

/// An object wrapping several components of a basic block hash. The combined
/// (blended) hash is represented and stored as one uint64_t, while individual
/// components are of smaller size (e.g., uint16_t or uint8_t).
struct BlendedBlockHash {
public:
explicit BlendedBlockHash(uint16_t Offset, uint16_t OpcodeHash,
uint16_t InstrHash, uint16_t NeighborHash)
: Offset(Offset), OpcodeHash(OpcodeHash), InstrHash(InstrHash),
NeighborHash(NeighborHash) {}

explicit BlendedBlockHash(uint64_t CombinedHash) {
Offset = CombinedHash & 0xffff;
CombinedHash >>= 16;
OpcodeHash = CombinedHash & 0xffff;
CombinedHash >>= 16;
InstrHash = CombinedHash & 0xffff;
CombinedHash >>= 16;
NeighborHash = CombinedHash & 0xffff;
}

/// Combine the blended hash into uint64_t.
uint64_t combine() const {

uint64_t Hash = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move these to the constructor and combine methods below. I don't think there is any point in defining these here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


Hash |= uint64_t(NeighborHash);
Hash <<= 16;

Hash |= uint64_t(InstrHash);
Hash <<= 16;

Hash |= uint64_t(OpcodeHash);
Hash <<= 16;

Hash |= uint64_t(Offset);

return Hash;
}

/// Compute a distance between two given blended hashes. The smaller the
/// distance, the more similar two blocks are. For identical basic blocks,
/// the distance is zero.
/// Since OpcodeHash is highly stable, we consider a match good only if
/// the OpcodeHashes are identical. Mismatched OpcodeHashes lead to low
/// matching accuracy, and poor matches undermine the quality of final
/// inference. Notably, during inference, we also consider the matching
/// ratio of basic blocks (BBs). For MachineFunctions with a low matching
/// ratio, we directly skip optimization to reduce the impact of
/// mismatches—this ensures even very poor profiles won’t cause negative
/// optimization.
/// In the context of matching, we consider NeighborHash to be more
/// important. This is especially true when accounting for inlining
/// scenarios, where the position of a basic block (BB) in the control
/// flow graph (CFG) is more critical. Therefore, the matching results
/// from NeighborHash carry greater significance.
uint64_t distance(const BlendedBlockHash &BBH) const {
assert(OpcodeHash == BBH.OpcodeHash &&
"incorrect blended hash distance computation");
uint64_t Dist = 0;
// Account for NeighborHash
Dist += NeighborHash == BBH.NeighborHash ? 0 : 1;
Dist <<= 16;
// Account for InstrHash
Dist += InstrHash == BBH.InstrHash ? 0 : 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The shifting in this method means NeighborHash is more important than InstrHash. Could you please explain this in the comments? Also why does opcode hash needs to be exactly the same in order to call this function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Yes, in the context of matching, we consider NeighborHash to be more important. This is especially true when accounting for inlining scenarios, where the position of a basic block (BB) in the control flow graph (CFG) is more critical. Therefore, the matching results from NeighborHash carry greater significance.
  2. Since OpcodeHash is highly stable, we consider a match good only if the OpcodeHashes are identical. Mismatched OpcodeHashes lead to low matching accuracy, and poor matches undermine the quality of final inference. Notably, during inference, we also consider the matching ratio of basic blocks (BBs). For MachineFunctions with a low matching ratio, we directly skip optimization to reduce the impact of mismatches—this ensures even very poor profiles won’t cause negative optimization.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please include this in the comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Dist <<= 16;
// Account for Offset
Dist += (Offset >= BBH.Offset ? Offset - BBH.Offset : BBH.Offset - Offset);
return Dist;
}

private:
/// The offset of the basic block from the function start.
uint16_t Offset{0};
/// Hash of the basic block instructions, excluding operands.
uint16_t OpcodeHash{0};
/// Hash of the basic block instructions, including opcodes and
/// operands.
uint16_t InstrHash{0};
/// OpcodeHash of the basic block together with OpcodeHashes of its
/// successors and predecessors.
uint16_t NeighborHash{0};
};

class MachineBlockHashInfo : public MachineFunctionPass {
DenseMap<const MachineBasicBlock *, uint64_t> MBBHashInfo;

public:
static char ID;
MachineBlockHashInfo();

StringRef getPassName() const override { return "Basic Block Hash Compute"; }

void getAnalysisUsage(AnalysisUsage &AU) const override;

bool runOnMachineFunction(MachineFunction &F) override;

uint64_t getMBBHash(const MachineBasicBlock &MBB);
};

} // end namespace llvm

#endif // LLVM_CODEGEN_MACHINEBLOCKHASHINFO_H
3 changes: 3 additions & 0 deletions llvm/include/llvm/CodeGen/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ LLVM_ABI MachineFunctionPass *createBasicBlockSectionsPass();

LLVM_ABI MachineFunctionPass *createBasicBlockPathCloningPass();

/// createMachineBlockHashInfoPass - This pass computes basic block hashes.
LLVM_ABI MachineFunctionPass *createMachineBlockHashInfoPass();

/// createMachineFunctionSplitterPass - This pass splits machine functions
/// using profile information.
LLVM_ABI MachineFunctionPass *createMachineFunctionSplitterPass();
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/InitializePasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ LLVM_ABI void initializeBasicBlockSectionsPass(PassRegistry &);
LLVM_ABI void initializeBarrierNoopPass(PassRegistry &);
LLVM_ABI void initializeBasicAAWrapperPassPass(PassRegistry &);
LLVM_ABI void initializeBlockFrequencyInfoWrapperPassPass(PassRegistry &);
LLVM_ABI void initializeMachineBlockHashInfoPass(PassRegistry &);
LLVM_ABI void initializeBranchFolderLegacyPass(PassRegistry &);
LLVM_ABI void initializeBranchProbabilityInfoWrapperPassPass(PassRegistry &);
LLVM_ABI void initializeBranchRelaxationLegacyPass(PassRegistry &);
Expand Down
21 changes: 15 additions & 6 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "llvm/CodeGen/GCMetadataPrinter.h"
#include "llvm/CodeGen/LazyMachineBlockFrequencyInfo.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineBlockHashInfo.h"
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineDominators.h"
Expand Down Expand Up @@ -184,6 +185,8 @@ static cl::opt<bool> PrintLatency(
cl::desc("Print instruction latencies as verbose asm comments"), cl::Hidden,
cl::init(false));

extern cl::opt<bool> EmitBBHash;

STATISTIC(EmittedInsts, "Number of machine instrs printed");

char AsmPrinter::ID = 0;
Expand Down Expand Up @@ -474,6 +477,8 @@ void AsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<GCModuleInfo>();
AU.addRequired<LazyMachineBlockFrequencyInfoPass>();
AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
if (EmitBBHash)
AU.addRequired<MachineBlockHashInfo>();
}

bool AsmPrinter::doInitialization(Module &M) {
Expand Down Expand Up @@ -1434,14 +1439,11 @@ getBBAddrMapFeature(const MachineFunction &MF, int NumMBBSectionRanges,
"BB entries info is required for BBFreq and BrProb "
"features");
}
return {FuncEntryCountEnabled,
BBFreqEnabled,
BrProbEnabled,
return {FuncEntryCountEnabled, BBFreqEnabled, BrProbEnabled,
MF.hasBBSections() && NumMBBSectionRanges > 1,
// Use static_cast to avoid breakage of tests on windows.
static_cast<bool>(BBAddrMapSkipEmitBBEntries),
HasCalls,
false};
static_cast<bool>(BBAddrMapSkipEmitBBEntries), HasCalls,
EmitBBHash.getValue()};
}

void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
Expand Down Expand Up @@ -1500,6 +1502,9 @@ void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
PrevMBBEndSymbol = MBBSymbol;
}

auto MBHI =
Features.BBHash ? &getAnalysis<MachineBlockHashInfo>() : nullptr;

if (!Features.OmitBBEntries) {
OutStreamer->AddComment("BB id");
// Emit the BB ID for this basic block.
Expand Down Expand Up @@ -1527,6 +1532,10 @@ void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
emitLabelDifferenceAsULEB128(MBB.getEndSymbol(), CurrentLabel);
// Emit the Metadata.
OutStreamer->emitULEB128IntValue(getBBAddrMapMetadata(MBB));
// Emit the Hash.
if (MBHI) {
OutStreamer->emitInt64(MBHI->getMBBHash(MBB));
}
}
PrevMBBEndSymbol = MBB.getEndSymbol();
}
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ add_llvm_component_library(LLVMCodeGen
LowerEmuTLS.cpp
MachineBasicBlock.cpp
MachineBlockFrequencyInfo.cpp
MachineBlockHashInfo.cpp
MachineBlockPlacement.cpp
MachineBranchProbabilityInfo.cpp
MachineCFGPrinter.cpp
Expand Down
114 changes: 114 additions & 0 deletions llvm/lib/CodeGen/MachineBlockHashInfo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//===- llvm/CodeGen/MachineBlockHashInfo.cpp---------------------*- 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
//
//===----------------------------------------------------------------------===//
//
// Compute the hashes of basic blocks.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/MachineBlockHashInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/InitializePasses.h"
#include "llvm/Target/TargetMachine.h"

using namespace llvm;

uint64_t hashBlock(const MachineBasicBlock &MBB, bool HashOperands) {
uint64_t Hash = 0;
for (const MachineInstr &MI : MBB) {
if (MI.isMetaInstruction() || MI.isTerminator())
continue;
Hash = hashing::detail::hash_16_bytes(Hash, MI.getOpcode());
if (HashOperands) {
for (unsigned i = 0; i < MI.getNumOperands(); i++) {
Hash =
hashing::detail::hash_16_bytes(Hash, hash_value(MI.getOperand(i)));
}
}
}
return Hash;
}

/// Fold a 64-bit integer to a 16-bit one.
uint16_t fold_64_to_16(const uint64_t Value) {
uint16_t Res = static_cast<uint16_t>(Value);
Res ^= static_cast<uint16_t>(Value >> 16);
Res ^= static_cast<uint16_t>(Value >> 32);
Res ^= static_cast<uint16_t>(Value >> 48);
return Res;
}

INITIALIZE_PASS(MachineBlockHashInfo, "machine-block-hash",
"Machine Block Hash Analysis", true, true)

char MachineBlockHashInfo::ID = 0;

MachineBlockHashInfo::MachineBlockHashInfo() : MachineFunctionPass(ID) {
initializeMachineBlockHashInfoPass(*PassRegistry::getPassRegistry());
}

void MachineBlockHashInfo::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
MachineFunctionPass::getAnalysisUsage(AU);
}

struct CollectHashInfo {
uint64_t Offset;
uint64_t OpcodeHash;
uint64_t InstrHash;
uint64_t NeighborHash;
};

bool MachineBlockHashInfo::runOnMachineFunction(MachineFunction &F) {
DenseMap<const MachineBasicBlock *, CollectHashInfo> HashInfos;
uint16_t Offset = 0;
// Initialize hash components
for (const MachineBasicBlock &MBB : F) {
// offset of the machine basic block
HashInfos[&MBB].Offset = Offset;
Offset += MBB.size();
// Hashing opcodes
HashInfos[&MBB].OpcodeHash = hashBlock(MBB, /*HashOperands=*/false);
// Hash complete instructions
HashInfos[&MBB].InstrHash = hashBlock(MBB, /*HashOperands=*/true);
}

// Initialize neighbor hash
for (const MachineBasicBlock &MBB : F) {
uint64_t Hash = HashInfos[&MBB].OpcodeHash;
// Append hashes of successors
for (const MachineBasicBlock *SuccMBB : MBB.successors()) {
uint64_t SuccHash = HashInfos[SuccMBB].OpcodeHash;
Hash = hashing::detail::hash_16_bytes(Hash, SuccHash);
}
// Append hashes of predecessors
for (const MachineBasicBlock *PredMBB : MBB.predecessors()) {
uint64_t PredHash = HashInfos[PredMBB].OpcodeHash;
Hash = hashing::detail::hash_16_bytes(Hash, PredHash);
}
HashInfos[&MBB].NeighborHash = Hash;
}

// Assign hashes
for (const MachineBasicBlock &MBB : F) {
BlendedBlockHash BlendedHash(fold_64_to_16(HashInfos[&MBB].Offset),
fold_64_to_16(HashInfos[&MBB].OpcodeHash),
fold_64_to_16(HashInfos[&MBB].InstrHash),
fold_64_to_16(HashInfos[&MBB].NeighborHash));
MBBHashInfo[&MBB] = BlendedHash.combine();
}

return false;
}

uint64_t MachineBlockHashInfo::getMBBHash(const MachineBasicBlock &MBB) {
return MBBHashInfo[&MBB];
}

MachineFunctionPass *llvm::createMachineBlockHashInfoPass() {
return new MachineBlockHashInfo();
}
8 changes: 8 additions & 0 deletions llvm/lib/CodeGen/TargetPassConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,12 @@ static cl::opt<bool>
cl::desc("Split static data sections into hot and cold "
"sections using profile information"));

cl::opt<bool> EmitBBHash(
"emit-bb-hash",
cl::desc(
"Emit the hash of basic block in the SHT_LLVM_BB_ADDR_MAP section."),
cl::init(false), cl::Optional);

/// Allow standard passes to be disabled by command line options. This supports
/// simple binary flags that either suppress the pass or do nothing.
/// i.e. -disable-mypass=false has no effect.
Expand Down Expand Up @@ -1281,6 +1287,8 @@ void TargetPassConfig::addMachinePasses() {
// address map (or both).
if (TM->getBBSectionsType() != llvm::BasicBlockSection::None ||
TM->Options.BBAddrMap) {
if (EmitBBHash)
addPass(llvm::createMachineBlockHashInfoPass());
if (TM->getBBSectionsType() == llvm::BasicBlockSection::List) {
addPass(llvm::createBasicBlockSectionsProfileReaderWrapperPass(
TM->getBBSectionsFuncListBuf()));
Expand Down
Loading