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