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