xref: /llvm-project/llvm/lib/IR/StructuralHash.cpp (revision 4f41862c5a5241654a37ee994ed0074a815d3633)
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