blob: 27110b014d2ec43f8b90a2553d625f7db42cc683 [file]
//===- 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();
}