120a7ea49SArthur Eubanks //===-- StructuralHash.cpp - IR Hashing -------------------------*- C++ -*-===// 2b1f4e597Sserge-sans-paille // 3b1f4e597Sserge-sans-paille // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4b1f4e597Sserge-sans-paille // See https://llvm.org/LICENSE.txt for license information. 5b1f4e597Sserge-sans-paille // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6b1f4e597Sserge-sans-paille // 7b1f4e597Sserge-sans-paille //===----------------------------------------------------------------------===// 8b1f4e597Sserge-sans-paille 9b1f4e597Sserge-sans-paille #include "llvm/IR/StructuralHash.h" 10b1f4e597Sserge-sans-paille #include "llvm/IR/Function.h" 11ce90dfc7SArthur Eubanks #include "llvm/IR/GlobalVariable.h" 12f532d61dSAiden Grossman #include "llvm/IR/InstrTypes.h" 13f532d61dSAiden Grossman #include "llvm/IR/Instructions.h" 14f532d61dSAiden Grossman #include "llvm/IR/IntrinsicInst.h" 15b1f4e597Sserge-sans-paille #include "llvm/IR/Module.h" 16b1f4e597Sserge-sans-paille 17b1f4e597Sserge-sans-paille using namespace llvm; 18b1f4e597Sserge-sans-paille 19b5776f10SArthur Eubanks namespace { 20b1f4e597Sserge-sans-paille 21b1f4e597Sserge-sans-paille // Basic hashing mechanism to detect structural change to the IR, used to verify 2209f4c696SAiden Grossman // pass return status consistency with actual change. In addition to being used 2309f4c696SAiden Grossman // by the MergeFunctions pass. 24b1f4e597Sserge-sans-paille 25b5776f10SArthur Eubanks class StructuralHashImpl { 261941c518SKyungwoo Lee stable_hash Hash = 4; 27b1f4e597Sserge-sans-paille 281941c518SKyungwoo Lee bool DetailedHash; 291941c518SKyungwoo Lee 301941c518SKyungwoo Lee // This random value acts as a block header, as otherwise the partition of 311941c518SKyungwoo Lee // opcodes into BBs wouldn't affect the hash, only the order of the opcodes. 321941c518SKyungwoo Lee static constexpr stable_hash BlockHeaderHash = 45798; 331941c518SKyungwoo Lee static constexpr stable_hash FunctionHeaderHash = 0x62642d6b6b2d6b72; 341941c518SKyungwoo Lee static constexpr stable_hash GlobalHeaderHash = 23456; 35b1f4e597Sserge-sans-paille 360dd9fdcfSKyungwoo Lee /// IgnoreOp is a function that returns true if the operand should be ignored. 370dd9fdcfSKyungwoo Lee IgnoreOperandFunc IgnoreOp = nullptr; 380dd9fdcfSKyungwoo Lee /// A mapping from instruction indices to instruction pointers. 390dd9fdcfSKyungwoo Lee /// The index represents the position of an instruction based on the order in 400dd9fdcfSKyungwoo Lee /// which it is first encountered. 410dd9fdcfSKyungwoo Lee std::unique_ptr<IndexInstrMap> IndexInstruction = nullptr; 420dd9fdcfSKyungwoo Lee /// A mapping from pairs of instruction indices and operand indices 430dd9fdcfSKyungwoo Lee /// to the hashes of the operands. 440dd9fdcfSKyungwoo Lee std::unique_ptr<IndexOperandHashMapType> IndexOperandHashMap = nullptr; 450dd9fdcfSKyungwoo Lee 460dd9fdcfSKyungwoo Lee /// Assign a unique ID to each Value in the order they are first seen. 470dd9fdcfSKyungwoo Lee DenseMap<const Value *, int> ValueToId; 48f532d61dSAiden Grossman 49*4f41862cSKyungwoo Lee static stable_hash hashType(Type *ValueType) { 501941c518SKyungwoo Lee SmallVector<stable_hash> Hashes; 511941c518SKyungwoo Lee Hashes.emplace_back(ValueType->getTypeID()); 52f532d61dSAiden Grossman if (ValueType->isIntegerTy()) 531941c518SKyungwoo Lee Hashes.emplace_back(ValueType->getIntegerBitWidth()); 541941c518SKyungwoo Lee return stable_hash_combine(Hashes); 55f532d61dSAiden Grossman } 56f532d61dSAiden Grossman 57b1f4e597Sserge-sans-paille public: 581941c518SKyungwoo Lee StructuralHashImpl() = delete; 590dd9fdcfSKyungwoo Lee explicit StructuralHashImpl(bool DetailedHash, 600dd9fdcfSKyungwoo Lee IgnoreOperandFunc IgnoreOp = nullptr) 610dd9fdcfSKyungwoo Lee : DetailedHash(DetailedHash), IgnoreOp(IgnoreOp) { 620dd9fdcfSKyungwoo Lee if (IgnoreOp) { 630dd9fdcfSKyungwoo Lee IndexInstruction = std::make_unique<IndexInstrMap>(); 640dd9fdcfSKyungwoo Lee IndexOperandHashMap = std::make_unique<IndexOperandHashMapType>(); 650dd9fdcfSKyungwoo Lee } 66f532d61dSAiden Grossman } 67f532d61dSAiden Grossman 68*4f41862cSKyungwoo Lee static stable_hash hashAPInt(const APInt &I) { 690dd9fdcfSKyungwoo Lee SmallVector<stable_hash> Hashes; 700dd9fdcfSKyungwoo Lee Hashes.emplace_back(I.getBitWidth()); 710dd9fdcfSKyungwoo Lee auto RawVals = ArrayRef<uint64_t>(I.getRawData(), I.getNumWords()); 720dd9fdcfSKyungwoo Lee Hashes.append(RawVals.begin(), RawVals.end()); 731941c518SKyungwoo Lee return stable_hash_combine(Hashes); 741941c518SKyungwoo Lee } 751941c518SKyungwoo Lee 76*4f41862cSKyungwoo Lee static stable_hash hashAPFloat(const APFloat &F) { 770dd9fdcfSKyungwoo Lee return hashAPInt(F.bitcastToAPInt()); 780dd9fdcfSKyungwoo Lee } 790dd9fdcfSKyungwoo Lee 80*4f41862cSKyungwoo Lee static stable_hash hashGlobalVariable(const GlobalVariable &GVar) { 81*4f41862cSKyungwoo Lee if (!GVar.hasInitializer()) 82*4f41862cSKyungwoo Lee return hashGlobalValue(&GVar); 83*4f41862cSKyungwoo Lee 84*4f41862cSKyungwoo Lee // Hash the contents of a string. 85*4f41862cSKyungwoo Lee if (GVar.getName().starts_with(".str")) { 86*4f41862cSKyungwoo Lee auto *C = GVar.getInitializer(); 87*4f41862cSKyungwoo Lee if (const auto *Seq = dyn_cast<ConstantDataSequential>(C)) 88*4f41862cSKyungwoo Lee if (Seq->isString()) 89*4f41862cSKyungwoo Lee return stable_hash_name(Seq->getAsString()); 90*4f41862cSKyungwoo Lee } 91*4f41862cSKyungwoo Lee 92*4f41862cSKyungwoo Lee // Hash structural contents of Objective-C metadata in specific sections. 93*4f41862cSKyungwoo Lee // This can be extended to other metadata if needed. 94*4f41862cSKyungwoo Lee static constexpr const char *SectionNames[] = { 95*4f41862cSKyungwoo Lee "__cfstring", "__cstring", "__objc_classrefs", 96*4f41862cSKyungwoo Lee "__objc_methname", "__objc_selrefs", 97*4f41862cSKyungwoo Lee }; 98*4f41862cSKyungwoo Lee if (GVar.hasSection()) { 99*4f41862cSKyungwoo Lee StringRef SectionName = GVar.getSection(); 100*4f41862cSKyungwoo Lee for (const char *Name : SectionNames) 101*4f41862cSKyungwoo Lee if (SectionName.contains(Name)) 102*4f41862cSKyungwoo Lee return hashConstant(GVar.getInitializer()); 103*4f41862cSKyungwoo Lee } 104*4f41862cSKyungwoo Lee 105*4f41862cSKyungwoo Lee return hashGlobalValue(&GVar); 106*4f41862cSKyungwoo Lee } 107*4f41862cSKyungwoo Lee 108*4f41862cSKyungwoo Lee static stable_hash hashGlobalValue(const GlobalValue *GV) { 1090dd9fdcfSKyungwoo Lee if (!GV->hasName()) 1100dd9fdcfSKyungwoo Lee return 0; 1110dd9fdcfSKyungwoo Lee return stable_hash_name(GV->getName()); 1120dd9fdcfSKyungwoo Lee } 1130dd9fdcfSKyungwoo Lee 1140dd9fdcfSKyungwoo Lee // Compute a hash for a Constant. This function is logically similar to 1150dd9fdcfSKyungwoo Lee // FunctionComparator::cmpConstants() in FunctionComparator.cpp, but here 1160dd9fdcfSKyungwoo Lee // we're interested in computing a hash rather than comparing two Constants. 1170dd9fdcfSKyungwoo Lee // Some of the logic is simplified, e.g, we don't expand GEPOperator. 118*4f41862cSKyungwoo Lee static stable_hash hashConstant(const Constant *C) { 1190dd9fdcfSKyungwoo Lee SmallVector<stable_hash> Hashes; 1200dd9fdcfSKyungwoo Lee 1210dd9fdcfSKyungwoo Lee Type *Ty = C->getType(); 1220dd9fdcfSKyungwoo Lee Hashes.emplace_back(hashType(Ty)); 1230dd9fdcfSKyungwoo Lee 1240dd9fdcfSKyungwoo Lee if (C->isNullValue()) { 1250dd9fdcfSKyungwoo Lee Hashes.emplace_back(static_cast<stable_hash>('N')); 1260dd9fdcfSKyungwoo Lee return stable_hash_combine(Hashes); 1270dd9fdcfSKyungwoo Lee } 1280dd9fdcfSKyungwoo Lee 129*4f41862cSKyungwoo Lee if (auto *GVar = dyn_cast<GlobalVariable>(C)) { 130*4f41862cSKyungwoo Lee Hashes.emplace_back(hashGlobalVariable(*GVar)); 131*4f41862cSKyungwoo Lee return stable_hash_combine(Hashes); 132*4f41862cSKyungwoo Lee } 133*4f41862cSKyungwoo Lee 1340dd9fdcfSKyungwoo Lee if (auto *G = dyn_cast<GlobalValue>(C)) { 1350dd9fdcfSKyungwoo Lee Hashes.emplace_back(hashGlobalValue(G)); 1360dd9fdcfSKyungwoo Lee return stable_hash_combine(Hashes); 1370dd9fdcfSKyungwoo Lee } 1380dd9fdcfSKyungwoo Lee 1390dd9fdcfSKyungwoo Lee if (const auto *Seq = dyn_cast<ConstantDataSequential>(C)) { 140*4f41862cSKyungwoo Lee if (Seq->isString()) { 141*4f41862cSKyungwoo Lee Hashes.emplace_back(stable_hash_name(Seq->getAsString())); 1420dd9fdcfSKyungwoo Lee return stable_hash_combine(Hashes); 1430dd9fdcfSKyungwoo Lee } 144*4f41862cSKyungwoo Lee } 1450dd9fdcfSKyungwoo Lee 1460dd9fdcfSKyungwoo Lee switch (C->getValueID()) { 1470dd9fdcfSKyungwoo Lee case Value::ConstantIntVal: { 1480dd9fdcfSKyungwoo Lee const APInt &Int = cast<ConstantInt>(C)->getValue(); 1490dd9fdcfSKyungwoo Lee Hashes.emplace_back(hashAPInt(Int)); 1500dd9fdcfSKyungwoo Lee return stable_hash_combine(Hashes); 1510dd9fdcfSKyungwoo Lee } 1520dd9fdcfSKyungwoo Lee case Value::ConstantFPVal: { 1530dd9fdcfSKyungwoo Lee const APFloat &APF = cast<ConstantFP>(C)->getValueAPF(); 1540dd9fdcfSKyungwoo Lee Hashes.emplace_back(hashAPFloat(APF)); 1550dd9fdcfSKyungwoo Lee return stable_hash_combine(Hashes); 1560dd9fdcfSKyungwoo Lee } 1570dd9fdcfSKyungwoo Lee case Value::ConstantArrayVal: 1580dd9fdcfSKyungwoo Lee case Value::ConstantStructVal: 1590dd9fdcfSKyungwoo Lee case Value::ConstantVectorVal: 1600dd9fdcfSKyungwoo Lee case Value::ConstantExprVal: { 1610dd9fdcfSKyungwoo Lee for (const auto &Op : C->operands()) { 1620dd9fdcfSKyungwoo Lee auto H = hashConstant(cast<Constant>(Op)); 1630dd9fdcfSKyungwoo Lee Hashes.emplace_back(H); 1640dd9fdcfSKyungwoo Lee } 1650dd9fdcfSKyungwoo Lee return stable_hash_combine(Hashes); 1660dd9fdcfSKyungwoo Lee } 1670dd9fdcfSKyungwoo Lee case Value::BlockAddressVal: { 1680dd9fdcfSKyungwoo Lee const BlockAddress *BA = cast<BlockAddress>(C); 1690dd9fdcfSKyungwoo Lee auto H = hashGlobalValue(BA->getFunction()); 1700dd9fdcfSKyungwoo Lee Hashes.emplace_back(H); 1710dd9fdcfSKyungwoo Lee return stable_hash_combine(Hashes); 1720dd9fdcfSKyungwoo Lee } 1730dd9fdcfSKyungwoo Lee case Value::DSOLocalEquivalentVal: { 1740dd9fdcfSKyungwoo Lee const auto *Equiv = cast<DSOLocalEquivalent>(C); 1750dd9fdcfSKyungwoo Lee auto H = hashGlobalValue(Equiv->getGlobalValue()); 1760dd9fdcfSKyungwoo Lee Hashes.emplace_back(H); 1770dd9fdcfSKyungwoo Lee return stable_hash_combine(Hashes); 1780dd9fdcfSKyungwoo Lee } 1790dd9fdcfSKyungwoo Lee default: 1800dd9fdcfSKyungwoo Lee // Skip other types of constants for simplicity. 1810dd9fdcfSKyungwoo Lee return stable_hash_combine(Hashes); 1820dd9fdcfSKyungwoo Lee } 1830dd9fdcfSKyungwoo Lee } 1840dd9fdcfSKyungwoo Lee 1851941c518SKyungwoo Lee stable_hash hashValue(Value *V) { 1861941c518SKyungwoo Lee // Check constant and return its hash. 1871941c518SKyungwoo Lee Constant *C = dyn_cast<Constant>(V); 1881941c518SKyungwoo Lee if (C) 1891941c518SKyungwoo Lee return hashConstant(C); 1901941c518SKyungwoo Lee 1911941c518SKyungwoo Lee // Hash argument number. 1921941c518SKyungwoo Lee SmallVector<stable_hash> Hashes; 1931941c518SKyungwoo Lee if (Argument *Arg = dyn_cast<Argument>(V)) 1941941c518SKyungwoo Lee Hashes.emplace_back(Arg->getArgNo()); 1951941c518SKyungwoo Lee 1960dd9fdcfSKyungwoo Lee // Get an index (an insertion order) for the non-constant value. 1970dd9fdcfSKyungwoo Lee auto [It, WasInserted] = ValueToId.try_emplace(V, ValueToId.size()); 1980dd9fdcfSKyungwoo Lee Hashes.emplace_back(It->second); 1990dd9fdcfSKyungwoo Lee 2001941c518SKyungwoo Lee return stable_hash_combine(Hashes); 2011941c518SKyungwoo Lee } 2021941c518SKyungwoo Lee 2031941c518SKyungwoo Lee stable_hash hashOperand(Value *Operand) { 2041941c518SKyungwoo Lee SmallVector<stable_hash> Hashes; 2051941c518SKyungwoo Lee Hashes.emplace_back(hashType(Operand->getType())); 2061941c518SKyungwoo Lee Hashes.emplace_back(hashValue(Operand)); 2071941c518SKyungwoo Lee return stable_hash_combine(Hashes); 2081941c518SKyungwoo Lee } 2091941c518SKyungwoo Lee 2101941c518SKyungwoo Lee stable_hash hashInstruction(const Instruction &Inst) { 2111941c518SKyungwoo Lee SmallVector<stable_hash> Hashes; 2121941c518SKyungwoo Lee Hashes.emplace_back(Inst.getOpcode()); 213f532d61dSAiden Grossman 214f532d61dSAiden Grossman if (!DetailedHash) 2151941c518SKyungwoo Lee return stable_hash_combine(Hashes); 216f532d61dSAiden Grossman 2171941c518SKyungwoo Lee Hashes.emplace_back(hashType(Inst.getType())); 218f532d61dSAiden Grossman 219f532d61dSAiden Grossman // Handle additional properties of specific instructions that cause 220f532d61dSAiden Grossman // semantic differences in the IR. 221f532d61dSAiden Grossman if (const auto *ComparisonInstruction = dyn_cast<CmpInst>(&Inst)) 2221941c518SKyungwoo Lee Hashes.emplace_back(ComparisonInstruction->getPredicate()); 223f532d61dSAiden Grossman 2240dd9fdcfSKyungwoo Lee unsigned InstIdx = 0; 2250dd9fdcfSKyungwoo Lee if (IndexInstruction) { 2260dd9fdcfSKyungwoo Lee InstIdx = IndexInstruction->size(); 2270dd9fdcfSKyungwoo Lee IndexInstruction->try_emplace(InstIdx, const_cast<Instruction *>(&Inst)); 2280dd9fdcfSKyungwoo Lee } 2290dd9fdcfSKyungwoo Lee 2300dd9fdcfSKyungwoo Lee for (const auto [OpndIdx, Op] : enumerate(Inst.operands())) { 2310dd9fdcfSKyungwoo Lee auto OpndHash = hashOperand(Op); 2320dd9fdcfSKyungwoo Lee if (IgnoreOp && IgnoreOp(&Inst, OpndIdx)) { 2330dd9fdcfSKyungwoo Lee assert(IndexOperandHashMap); 2340dd9fdcfSKyungwoo Lee IndexOperandHashMap->try_emplace({InstIdx, OpndIdx}, OpndHash); 2350dd9fdcfSKyungwoo Lee } else 2360dd9fdcfSKyungwoo Lee Hashes.emplace_back(OpndHash); 2370dd9fdcfSKyungwoo Lee } 2381941c518SKyungwoo Lee 2391941c518SKyungwoo Lee return stable_hash_combine(Hashes); 240f532d61dSAiden Grossman } 241f532d61dSAiden Grossman 24264da0be1SAiden Grossman // A function hash is calculated by considering only the number of arguments 24364da0be1SAiden Grossman // and whether a function is varargs, the order of basic blocks (given by the 24464da0be1SAiden Grossman // successors of each basic block in depth first order), and the order of 24564da0be1SAiden Grossman // opcodes of each instruction within each of these basic blocks. This mirrors 24664da0be1SAiden Grossman // the strategy FunctionComparator::compare() uses to compare functions by 24764da0be1SAiden Grossman // walking the BBs in depth first order and comparing each instruction in 24864da0be1SAiden Grossman // sequence. Because this hash currently does not look at the operands, it is 24964da0be1SAiden Grossman // insensitive to things such as the target of calls and the constants used in 25064da0be1SAiden Grossman // the function, which makes it useful when possibly merging functions which 25164da0be1SAiden Grossman // are the same modulo constants and call targets. 25264da0be1SAiden Grossman // 25364da0be1SAiden Grossman // Note that different users of StructuralHash will want different behavior 25464da0be1SAiden Grossman // out of it (i.e., MergeFunctions will want something different from PM 25564da0be1SAiden Grossman // expensive checks for pass modification status). When modifying this 25664da0be1SAiden Grossman // function, most changes should be gated behind an option and enabled 25764da0be1SAiden Grossman // selectively. 2581941c518SKyungwoo Lee void update(const Function &F) { 259ce90dfc7SArthur Eubanks // Declarations don't affect analyses. 260ce90dfc7SArthur Eubanks if (F.isDeclaration()) 261b1f4e597Sserge-sans-paille return; 262b1f4e597Sserge-sans-paille 2631941c518SKyungwoo Lee SmallVector<stable_hash> Hashes; 2641941c518SKyungwoo Lee Hashes.emplace_back(Hash); 2651941c518SKyungwoo Lee Hashes.emplace_back(FunctionHeaderHash); 266ce90dfc7SArthur Eubanks 2671941c518SKyungwoo Lee Hashes.emplace_back(F.isVarArg()); 2681941c518SKyungwoo Lee Hashes.emplace_back(F.arg_size()); 269b1f4e597Sserge-sans-paille 270b1f4e597Sserge-sans-paille SmallVector<const BasicBlock *, 8> BBs; 271b1f4e597Sserge-sans-paille SmallPtrSet<const BasicBlock *, 16> VisitedBBs; 272b1f4e597Sserge-sans-paille 27364da0be1SAiden Grossman // Walk the blocks in the same order as 27464da0be1SAiden Grossman // FunctionComparator::cmpBasicBlocks(), accumulating the hash of the 27564da0be1SAiden Grossman // function "structure." (BB and opcode sequence) 276b1f4e597Sserge-sans-paille BBs.push_back(&F.getEntryBlock()); 277b1f4e597Sserge-sans-paille VisitedBBs.insert(BBs[0]); 278b1f4e597Sserge-sans-paille while (!BBs.empty()) { 279b1f4e597Sserge-sans-paille const BasicBlock *BB = BBs.pop_back_val(); 28064da0be1SAiden Grossman 2811941c518SKyungwoo Lee Hashes.emplace_back(BlockHeaderHash); 282b1f4e597Sserge-sans-paille for (auto &Inst : *BB) 2831941c518SKyungwoo Lee Hashes.emplace_back(hashInstruction(Inst)); 284b1f4e597Sserge-sans-paille 285fd358997SKazu Hirata for (const BasicBlock *Succ : successors(BB)) 286fd358997SKazu Hirata if (VisitedBBs.insert(Succ).second) 287fd358997SKazu Hirata BBs.push_back(Succ); 288b1f4e597Sserge-sans-paille } 2891941c518SKyungwoo Lee 2901941c518SKyungwoo Lee // Update the combined hash in place. 2911941c518SKyungwoo Lee Hash = stable_hash_combine(Hashes); 292b1f4e597Sserge-sans-paille } 293b1f4e597Sserge-sans-paille 294ce90dfc7SArthur Eubanks void update(const GlobalVariable &GV) { 295d2640f59SMikael Holmen // Declarations and used/compiler.used don't affect analyses. 296e8e499f5SPaul Kirth // Since there are several `llvm.*` metadata, like `llvm.embedded.object`, 297e8e499f5SPaul Kirth // we ignore anything with the `.llvm` prefix 298e8e499f5SPaul Kirth if (GV.isDeclaration() || GV.getName().starts_with("llvm.")) 299ce90dfc7SArthur Eubanks return; 3001941c518SKyungwoo Lee SmallVector<stable_hash> Hashes; 3011941c518SKyungwoo Lee Hashes.emplace_back(Hash); 3021941c518SKyungwoo Lee Hashes.emplace_back(GlobalHeaderHash); 3031941c518SKyungwoo Lee Hashes.emplace_back(GV.getValueType()->getTypeID()); 3041941c518SKyungwoo Lee 3051941c518SKyungwoo Lee // Update the combined hash in place. 3061941c518SKyungwoo Lee Hash = stable_hash_combine(Hashes); 307ce90dfc7SArthur Eubanks } 308ce90dfc7SArthur Eubanks 3091941c518SKyungwoo Lee void update(const Module &M) { 310ce90dfc7SArthur Eubanks for (const GlobalVariable &GV : M.globals()) 311ce90dfc7SArthur Eubanks update(GV); 312b1f4e597Sserge-sans-paille for (const Function &F : M) 3131941c518SKyungwoo Lee update(F); 314b1f4e597Sserge-sans-paille } 315b1f4e597Sserge-sans-paille 316b1f4e597Sserge-sans-paille uint64_t getHash() const { return Hash; } 3170dd9fdcfSKyungwoo Lee 3180dd9fdcfSKyungwoo Lee std::unique_ptr<IndexInstrMap> getIndexInstrMap() { 3190dd9fdcfSKyungwoo Lee return std::move(IndexInstruction); 3200dd9fdcfSKyungwoo Lee } 3210dd9fdcfSKyungwoo Lee 3220dd9fdcfSKyungwoo Lee std::unique_ptr<IndexOperandHashMapType> getIndexPairOpndHashMap() { 3230dd9fdcfSKyungwoo Lee return std::move(IndexOperandHashMap); 3240dd9fdcfSKyungwoo Lee } 325b1f4e597Sserge-sans-paille }; 326b1f4e597Sserge-sans-paille 327b5776f10SArthur Eubanks } // namespace 328b1f4e597Sserge-sans-paille 3291941c518SKyungwoo Lee stable_hash llvm::StructuralHash(const Function &F, bool DetailedHash) { 3301941c518SKyungwoo Lee StructuralHashImpl H(DetailedHash); 3311941c518SKyungwoo Lee H.update(F); 332b1f4e597Sserge-sans-paille return H.getHash(); 333b1f4e597Sserge-sans-paille } 334b1f4e597Sserge-sans-paille 335*4f41862cSKyungwoo Lee stable_hash llvm::StructuralHash(const GlobalVariable &GVar) { 336*4f41862cSKyungwoo Lee return StructuralHashImpl::hashGlobalVariable(GVar); 337*4f41862cSKyungwoo Lee } 338*4f41862cSKyungwoo Lee 3391941c518SKyungwoo Lee stable_hash llvm::StructuralHash(const Module &M, bool DetailedHash) { 3401941c518SKyungwoo Lee StructuralHashImpl H(DetailedHash); 3411941c518SKyungwoo Lee H.update(M); 342b1f4e597Sserge-sans-paille return H.getHash(); 343b1f4e597Sserge-sans-paille } 3440dd9fdcfSKyungwoo Lee 3450dd9fdcfSKyungwoo Lee FunctionHashInfo 3460dd9fdcfSKyungwoo Lee llvm::StructuralHashWithDifferences(const Function &F, 3470dd9fdcfSKyungwoo Lee IgnoreOperandFunc IgnoreOp) { 3480dd9fdcfSKyungwoo Lee StructuralHashImpl H(/*DetailedHash=*/true, IgnoreOp); 3490dd9fdcfSKyungwoo Lee H.update(F); 3500dd9fdcfSKyungwoo Lee return FunctionHashInfo(H.getHash(), H.getIndexInstrMap(), 3510dd9fdcfSKyungwoo Lee H.getIndexPairOpndHashMap()); 3520dd9fdcfSKyungwoo Lee } 353