Index: llvm/include/llvm/IR/StructuralHash.h =================================================================== --- /dev/null +++ llvm/include/llvm/IR/StructuralHash.h @@ -0,0 +1,40 @@ +//===- llvm/IR/StructuralHash.h - Hash Function & Module for expensive checks +//--*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides hashing of the LLVM IR structure to be used to check +// Passes modification status. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_STRUCTURALHASH_H +#define LLVM_IR_STRUCTURALHASH_H + +#include + +// This header is only meant to be used when -DEXPENSIVE_CHECKS is set +namespace llvm { + +class Function; +class Module; + +#ifdef EXPENSIVE_CHECKS + +uint64_t StructuralHash(Function const &F); +uint64_t StructuralHash(Module const &M); + +#else + +static inline uint64_t StructuralHash(Function const &F) { return 0; } +static inline uint64_t StructuralHash(Module const &M) { return 0; } + +#endif + +} // end namespace llvm + +#endif // LLVM_IR_STRUCTURALHASH_H Index: llvm/lib/Analysis/CallGraphSCCPass.cpp =================================================================== --- llvm/lib/Analysis/CallGraphSCCPass.cpp +++ llvm/lib/Analysis/CallGraphSCCPass.cpp @@ -28,6 +28,7 @@ #include "llvm/IR/Module.h" #include "llvm/IR/OptBisect.h" #include "llvm/IR/PassTimingInfo.h" +#include "llvm/IR/StructuralHash.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -466,10 +467,15 @@ initializeAnalysisImpl(P); + uint64_t RefHash = StructuralHash(CG.getModule()); + // Actually run this pass on the current SCC. bool LocalChanged = RunPassOnSCC(P, CurSCC, CG, CallGraphUpToDate, DevirtualizedCall); + assert((LocalChanged || (RefHash == StructuralHash(CG.getModule()))) && + "Pass modifies its input and doesn't report it."); + Changed |= LocalChanged; if (LocalChanged) Index: llvm/lib/Analysis/LoopPass.cpp =================================================================== --- llvm/lib/Analysis/LoopPass.cpp +++ llvm/lib/Analysis/LoopPass.cpp @@ -20,6 +20,7 @@ #include "llvm/IR/OptBisect.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/PassTimingInfo.h" +#include "llvm/IR/StructuralHash.h" #include "llvm/InitializePasses.h" #include "llvm/Support/Debug.h" #include "llvm/Support/TimeProfiler.h" @@ -191,7 +192,14 @@ { PassManagerPrettyStackEntry X(P, *CurrentLoop->getHeader()); TimeRegion PassTimer(getPassTimer(P)); + + uint64_t RefHash = StructuralHash(F); + LocalChanged = P->runOnLoop(CurrentLoop, *this); + + assert((LocalChanged || (RefHash == StructuralHash(F))) && + "Pass modifies its input and doesn't report it."); + Changed |= LocalChanged; if (EmitICRemark) { unsigned NewSize = F.getInstructionCount(); Index: llvm/lib/Analysis/RegionPass.cpp =================================================================== --- llvm/lib/Analysis/RegionPass.cpp +++ llvm/lib/Analysis/RegionPass.cpp @@ -15,6 +15,7 @@ #include "llvm/Analysis/RegionPass.h" #include "llvm/IR/OptBisect.h" #include "llvm/IR/PassTimingInfo.h" +#include "llvm/IR/StructuralHash.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" @@ -94,9 +95,14 @@ { PassManagerPrettyStackEntry X(P, *CurrentRegion->getEntry()); + uint64_t RefHash = StructuralHash(F); + TimeRegion PassTimer(getPassTimer(P)); LocalChanged = P->runOnRegion(CurrentRegion, *this); Changed |= LocalChanged; + + assert((LocalChanged || (RefHash == StructuralHash(F))) && + "Pass modifies its input and doesn't report it."); } if (isPassDebuggingExecutionsOrMore()) { Index: llvm/lib/IR/CMakeLists.txt =================================================================== --- llvm/lib/IR/CMakeLists.txt +++ llvm/lib/IR/CMakeLists.txt @@ -47,6 +47,7 @@ SafepointIRVerifier.cpp ProfileSummary.cpp Statepoint.cpp + StructuralHash.cpp Type.cpp TypeFinder.cpp Use.cpp Index: llvm/lib/IR/LegacyPassManager.cpp =================================================================== --- llvm/lib/IR/LegacyPassManager.cpp +++ llvm/lib/IR/LegacyPassManager.cpp @@ -20,6 +20,7 @@ #include "llvm/IR/LegacyPassNameParser.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassTimingInfo.h" +#include "llvm/IR/StructuralHash.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -1475,75 +1476,6 @@ } } -#ifdef EXPENSIVE_CHECKS -namespace { -namespace details { - -// Basic hashing mechanism to detect structural change to the IR, used to verify -// pass return status consistency with actual change. Loosely copied from -// llvm/lib/Transforms/Utils/FunctionComparator.cpp - -class StructuralHash { - uint64_t Hash = 0x6acaa36bef8325c5ULL; - - void update(uint64_t V) { Hash = hashing::detail::hash_16_bytes(Hash, V); } - -public: - StructuralHash() = default; - - void update(Function &F) { - if (F.empty()) - return; - - update(F.isVarArg()); - update(F.arg_size()); - - SmallVector BBs; - SmallPtrSet VisitedBBs; - - BBs.push_back(&F.getEntryBlock()); - VisitedBBs.insert(BBs[0]); - while (!BBs.empty()) { - const BasicBlock *BB = BBs.pop_back_val(); - update(45798); // Block header - for (auto &Inst : *BB) - update(Inst.getOpcode()); - - const Instruction *Term = BB->getTerminator(); - for (unsigned i = 0, e = Term->getNumSuccessors(); i != e; ++i) { - if (!VisitedBBs.insert(Term->getSuccessor(i)).second) - continue; - BBs.push_back(Term->getSuccessor(i)); - } - } - } - - void update(Module &M) { - for (Function &F : M) - update(F); - } - - uint64_t getHash() const { return Hash; } -}; - -} // namespace details - -uint64_t StructuralHash(Function &F) { - details::StructuralHash H; - H.update(F); - return H.getHash(); -} - -uint64_t StructuralHash(Module &M) { - details::StructuralHash H; - H.update(M); - return H.getHash(); -} - -} // end anonymous namespace - -#endif - /// Execute all of the passes scheduled for execution by invoking /// runOnFunction method. Keep track of whether any of the passes modifies /// the function, and if so, return true. @@ -1581,15 +1513,13 @@ { PassManagerPrettyStackEntry X(FP, F); TimeRegion PassTimer(getPassTimer(FP)); -#ifdef EXPENSIVE_CHECKS + uint64_t RefHash = StructuralHash(F); -#endif + LocalChanged |= FP->runOnFunction(F); -#ifdef EXPENSIVE_CHECKS assert((LocalChanged || (RefHash == StructuralHash(F))) && "Pass modifies its input and doesn't report it."); -#endif if (EmitICRemark) { unsigned NewSize = F.getInstructionCount(); @@ -1692,16 +1622,12 @@ PassManagerPrettyStackEntry X(MP, M); TimeRegion PassTimer(getPassTimer(MP)); -#ifdef EXPENSIVE_CHECKS uint64_t RefHash = StructuralHash(M); -#endif LocalChanged |= MP->runOnModule(M); -#ifdef EXPENSIVE_CHECKS assert((LocalChanged || (RefHash == StructuralHash(M))) && "Pass modifies its input and doesn't report it."); -#endif if (EmitICRemark) { // Update the size of the module. Index: llvm/lib/IR/StructuralHash.cpp =================================================================== --- /dev/null +++ llvm/lib/IR/StructuralHash.cpp @@ -0,0 +1,85 @@ +//===-- StructuralHash.cpp - Hash Function & Module for expensive checks +//----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// + +#ifdef EXPENSIVE_CHECKS + +#include "llvm/IR/StructuralHash.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Module.h" + +using namespace llvm; + +namespace { +namespace details { + +// Basic hashing mechanism to detect structural change to the IR, used to verify +// pass return status consistency with actual change. Loosely copied from +// llvm/lib/Transforms/Utils/FunctionComparator.cpp + +class StructuralHash { + uint64_t Hash = 0x6acaa36bef8325c5ULL; + + void update(uint64_t V) { Hash = hashing::detail::hash_16_bytes(Hash, V); } + +public: + StructuralHash() = default; + + void update(Function const &F) { + if (F.empty()) + return; + + update(F.isVarArg()); + update(F.arg_size()); + + SmallVector BBs; + SmallPtrSet VisitedBBs; + + BBs.push_back(&F.getEntryBlock()); + VisitedBBs.insert(BBs[0]); + while (!BBs.empty()) { + const BasicBlock *BB = BBs.pop_back_val(); + update(45798); // Block header + for (auto &Inst : *BB) + update(Inst.getOpcode()); + + const Instruction *Term = BB->getTerminator(); + for (unsigned i = 0, e = Term->getNumSuccessors(); i != e; ++i) { + if (!VisitedBBs.insert(Term->getSuccessor(i)).second) + continue; + BBs.push_back(Term->getSuccessor(i)); + } + } + } + + void update(Module const &M) { + for (Function const &F : M) + update(F); + } + + uint64_t getHash() const { return Hash; } +}; + +} // namespace details + +} // namespace + +uint64_t llvm::StructuralHash(Function const &F) { + details::StructuralHash H; + H.update(F); + return H.getHash(); +} + +uint64_t llvm::StructuralHash(Module const &M) { + details::StructuralHash H; + H.update(M); + return H.getHash(); +} + +#endif