//===- 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(Value); Res ^= static_cast(Value >> 16); Res ^= static_cast(Value >> 32); Res ^= static_cast(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 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(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(); }