Index: llvm/lib/IR/LegacyPassManager.cpp =================================================================== --- llvm/lib/IR/LegacyPassManager.cpp +++ llvm/lib/IR/LegacyPassManager.cpp @@ -1441,6 +1441,66 @@ } } +#ifdef EXPENSIVE_CHECKS +namespace { + +// 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; + +public: + StructuralHash() = default; + + void add(uint64_t V) { Hash = hashing::detail::hash_16_bytes(Hash, V); } + + uint64_t getHash() { return Hash; } +}; + +uint64_t functionHash(Function &F, StructuralHash &H) { + if (F.empty()) + return H.getHash(); + + H.add(F.isVarArg()); + H.add(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(); + H.add(45798); // Block header + for (auto &Inst : *BB) + H.add(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)); + } + } + return H.getHash(); +} + +uint64_t FunctionHash(Function &F) { + StructuralHash H; + return functionHash(F, H); +} + +uint64_t ModuleHash(Module &M) { + StructuralHash H; + for (auto &F : M) + functionHash(F, H); + 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 @@ -1479,7 +1539,16 @@ { PassManagerPrettyStackEntry X(FP, F); TimeRegion PassTimer(getPassTimer(FP)); +#ifdef EXPENSIVE_CHECKS + uint64_t RefHash = FunctionHash(F); +#endif LocalChanged |= FP->runOnFunction(F); + +#ifdef EXPENSIVE_CHECKS + assert((LocalChanged || (RefHash == FunctionHash(F))) && + "Pass modifies its input and doesn't report it."); +#endif + if (EmitICRemark) { unsigned NewSize = F.getInstructionCount(); @@ -1580,7 +1649,17 @@ PassManagerPrettyStackEntry X(MP, M); TimeRegion PassTimer(getPassTimer(MP)); +#ifdef EXPENSIVE_CHECKS + uint64_t RefHash = ModuleHash(M); +#endif + LocalChanged |= MP->runOnModule(M); + +#ifdef EXPENSIVE_CHECKS + assert((LocalChanged || (RefHash == ModuleHash(M))) && + "Pass modifies its input and doesn't report it."); +#endif + if (EmitICRemark) { // Update the size of the module. unsigned ModuleCount = M.getInstructionCount(); Index: llvm/unittests/IR/LegacyPassManagerTest.cpp =================================================================== --- llvm/unittests/IR/LegacyPassManagerTest.cpp +++ llvm/unittests/IR/LegacyPassManagerTest.cpp @@ -680,7 +680,7 @@ ASSERT_EQ(M->getFunctionList().size(), 4U); Function *F = M->getFunction("test2"); Function *SF = splitSimpleFunction(*F); - CallInst::Create(F, "", &SF->getEntryBlock()); + CallInst::Create(F, "", &*SF->getEntryBlock().getFirstInsertionPt()); ASSERT_EQ(M->getFunctionList().size(), 5U); CGModifierPass *P = new CGModifierPass(); legacy::PassManager Passes;