1*af732203SDimitry Andric //===-- StructuralHash.cpp - IR Hash for expensive checks -------*- C++ -*-===//
2*af732203SDimitry Andric //
3*af732203SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*af732203SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*af732203SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*af732203SDimitry Andric //
7*af732203SDimitry Andric //===----------------------------------------------------------------------===//
8*af732203SDimitry Andric //
9*af732203SDimitry Andric 
10*af732203SDimitry Andric #ifdef EXPENSIVE_CHECKS
11*af732203SDimitry Andric 
12*af732203SDimitry Andric #include "llvm/IR/StructuralHash.h"
13*af732203SDimitry Andric #include "llvm/IR/Function.h"
14*af732203SDimitry Andric #include "llvm/IR/Module.h"
15*af732203SDimitry Andric 
16*af732203SDimitry Andric using namespace llvm;
17*af732203SDimitry Andric 
18*af732203SDimitry Andric namespace {
19*af732203SDimitry Andric namespace details {
20*af732203SDimitry Andric 
21*af732203SDimitry Andric // Basic hashing mechanism to detect structural change to the IR, used to verify
22*af732203SDimitry Andric // pass return status consistency with actual change. Loosely copied from
23*af732203SDimitry Andric // llvm/lib/Transforms/Utils/FunctionComparator.cpp
24*af732203SDimitry Andric 
25*af732203SDimitry Andric class StructuralHash {
26*af732203SDimitry Andric   uint64_t Hash = 0x6acaa36bef8325c5ULL;
27*af732203SDimitry Andric 
update(uint64_t V)28*af732203SDimitry Andric   void update(uint64_t V) { Hash = hashing::detail::hash_16_bytes(Hash, V); }
29*af732203SDimitry Andric 
30*af732203SDimitry Andric public:
31*af732203SDimitry Andric   StructuralHash() = default;
32*af732203SDimitry Andric 
update(const Function & F)33*af732203SDimitry Andric   void update(const Function &F) {
34*af732203SDimitry Andric     if (F.empty())
35*af732203SDimitry Andric       return;
36*af732203SDimitry Andric 
37*af732203SDimitry Andric     update(F.isVarArg());
38*af732203SDimitry Andric     update(F.arg_size());
39*af732203SDimitry Andric 
40*af732203SDimitry Andric     SmallVector<const BasicBlock *, 8> BBs;
41*af732203SDimitry Andric     SmallPtrSet<const BasicBlock *, 16> VisitedBBs;
42*af732203SDimitry Andric 
43*af732203SDimitry Andric     BBs.push_back(&F.getEntryBlock());
44*af732203SDimitry Andric     VisitedBBs.insert(BBs[0]);
45*af732203SDimitry Andric     while (!BBs.empty()) {
46*af732203SDimitry Andric       const BasicBlock *BB = BBs.pop_back_val();
47*af732203SDimitry Andric       update(45798); // Block header
48*af732203SDimitry Andric       for (auto &Inst : *BB)
49*af732203SDimitry Andric         update(Inst.getOpcode());
50*af732203SDimitry Andric 
51*af732203SDimitry Andric       const Instruction *Term = BB->getTerminator();
52*af732203SDimitry Andric       for (unsigned i = 0, e = Term->getNumSuccessors(); i != e; ++i) {
53*af732203SDimitry Andric         if (!VisitedBBs.insert(Term->getSuccessor(i)).second)
54*af732203SDimitry Andric           continue;
55*af732203SDimitry Andric         BBs.push_back(Term->getSuccessor(i));
56*af732203SDimitry Andric       }
57*af732203SDimitry Andric     }
58*af732203SDimitry Andric   }
59*af732203SDimitry Andric 
update(const Module & M)60*af732203SDimitry Andric   void update(const Module &M) {
61*af732203SDimitry Andric     for (const Function &F : M)
62*af732203SDimitry Andric       update(F);
63*af732203SDimitry Andric   }
64*af732203SDimitry Andric 
getHash() const65*af732203SDimitry Andric   uint64_t getHash() const { return Hash; }
66*af732203SDimitry Andric };
67*af732203SDimitry Andric 
68*af732203SDimitry Andric } // namespace details
69*af732203SDimitry Andric 
70*af732203SDimitry Andric } // namespace
71*af732203SDimitry Andric 
StructuralHash(const Function & F)72*af732203SDimitry Andric uint64_t llvm::StructuralHash(const Function &F) {
73*af732203SDimitry Andric   details::StructuralHash H;
74*af732203SDimitry Andric   H.update(F);
75*af732203SDimitry Andric   return H.getHash();
76*af732203SDimitry Andric }
77*af732203SDimitry Andric 
StructuralHash(const Module & M)78*af732203SDimitry Andric uint64_t llvm::StructuralHash(const Module &M) {
79*af732203SDimitry Andric   details::StructuralHash H;
80*af732203SDimitry Andric   H.update(M);
81*af732203SDimitry Andric   return H.getHash();
82*af732203SDimitry Andric }
83*af732203SDimitry Andric 
84*af732203SDimitry Andric #endif
85