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 Andricuint64_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 Andricuint64_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