//===- 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; 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. 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 in the control /// flow graph is more critical. 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; Dist <<= 16; // Account for Offset Dist += (Offset >= BBH.Offset ? Offset - BBH.Offset : BBH.Offset - Offset); return Dist; } uint16_t getOpcodeHash() const { return OpcodeHash; } 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 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