`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.
159 lines
5.3 KiB
C++
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();
|
|
}
|