Files
llvm-project/llvm/lib/CodeGen/MachineBlockHashInfo.cpp
Vitaly Buka 440872232b [NFC][MachineBlockHashInfo] Add static asserts to guard agains hash_16_bytes changes (#192862)
`hashing::detail::hash_16_bytes` is not guaranteed to be stable across
different versions of LLVM, it can change any time.

We put asserts here, so if it changed, author don't forget to work
around them here.
2026-04-22 18:25:06 +00:00

159 lines
5.3 KiB
C++

//===- 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/ADT/Hashing.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineStableHash.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
using namespace llvm;
static 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, stableHashValue(MI.getOperand(i)));
}
}
}
return Hash;
}
/// Fold a 64-bit integer to a 16-bit one.
static constexpr 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;
}
// Keep stable to serialize data.
static_assert(hashing::detail::hash_16_bytes(1, 2) == 9684580150926652833ull,
"Hash function must be stable");
static_assert(hashing::detail::hash_16_bytes(-1, -2) == 7819786907124864172ull,
"Hash function must be stable");
static_assert(fold_64_to_16(1) == 1, "Fold function must be stable");
static_assert(fold_64_to_16(12345678) == 25074, "Fold function must be stable");
INITIALIZE_PASS(MachineBlockHashInfo, "machine-block-hash",
"Machine Block Hash Analysis", true, true)
char MachineBlockHashInfo::ID = 0;
MachineBlockHashInfo::MachineBlockHashInfo() : MachineFunctionPass(ID) {}
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;
};
MachineBlockHashInfoResult::MachineBlockHashInfoResult() = default;
MachineBlockHashInfoResult::MachineBlockHashInfoResult(
const MachineFunction &F) {
DenseMap<const MachineBasicBlock *, CollectHashInfo> HashInfos;
uint16_t Offset = 0;
// Initialize hash components
for (const MachineBasicBlock &MBB : F) {
auto &HashInfo = HashInfos[&MBB];
// offset of the machine basic block
HashInfo.Offset = Offset + MBB.size();
// Hashing opcodes
HashInfo.OpcodeHash = hashBlock(MBB, /*HashOperands=*/false);
// Hash complete instructions
HashInfo.InstrHash = hashBlock(MBB, /*HashOperands=*/true);
}
// Initialize neighbor hash
for (const MachineBasicBlock &MBB : F) {
auto &HashInfo = HashInfos[&MBB];
uint64_t Hash = HashInfo.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);
}
HashInfo.NeighborHash = Hash;
}
// Assign hashes
for (const MachineBasicBlock &MBB : F) {
const auto &HashInfo = HashInfos[&MBB];
BlendedBlockHash BlendedHash(fold_64_to_16(HashInfo.Offset),
fold_64_to_16(HashInfo.OpcodeHash),
fold_64_to_16(HashInfo.InstrHash),
fold_64_to_16(HashInfo.NeighborHash));
MBBHashInfo[&MBB] = BlendedHash.combine();
}
}
uint64_t
MachineBlockHashInfoResult::getMBBHash(const MachineBasicBlock &MBB) const {
auto it = MBBHashInfo.find(&MBB);
return it->second;
}
bool MachineBlockHashInfo::runOnMachineFunction(MachineFunction &F) {
Result = MachineBlockHashInfoResult{F};
return false;
}
uint64_t MachineBlockHashInfo::getMBBHash(const MachineBasicBlock &MBB) const {
return Result.getMBBHash(MBB);
}
MachineFunctionPass *llvm::createMachineBlockHashInfoPass() {
return new MachineBlockHashInfo();
}
AnalysisKey MachineBlockHashInfoAnalysis::Key;
MachineBlockHashInfoResult
MachineBlockHashInfoAnalysis::run(MachineFunction &MF,
MachineFunctionAnalysisManager &MFAM) {
return MachineBlockHashInfoResult{MF};
}
PreservedAnalyses
MachineBlockHashInfoPrinterPass::run(MachineFunction &MF,
MachineFunctionAnalysisManager &MFAM) {
auto &MBHI = MFAM.getResult<MachineBlockHashInfoAnalysis>(MF);
OS << "Machine Block Hash Info for function: " << MF.getName() << "\n";
for (const auto &MBB : MF) {
OS << " BB#" << MBB.getNumber() << ": "
<< format_hex(MBHI.getMBBHash(MBB), 16) << "\n";
}
return PreservedAnalyses::all();
}