Index: llvm/lib/IR/LegacyPassManager.cpp =================================================================== --- llvm/lib/IR/LegacyPassManager.cpp +++ llvm/lib/IR/LegacyPassManager.cpp @@ -1441,6 +1441,65 @@ } } +#ifndef NDEBUG +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 HashAccumulator64 { + uint64_t Hash = 0x6acaa36bef8325c5ULL; + +public: + HashAccumulator64() = default; + + void add(uint64_t V) { Hash = hashing::detail::hash_16_bytes(Hash, V); } + + uint64_t getHash() { return Hash; } +}; + +uint64_t functionHash(Function &F, HashAccumulator64 &H) { + H.add(F.isVarArg()); + H.add(F.arg_size()); + if (F.isDeclaration()) + return H.getHash(); + + 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) { + HashAccumulator64 H; + return functionHash(F, H); +} + +uint64_t ModuleHash(Module &M) { + HashAccumulator64 H; + for (auto &F : M) + functionHash(F); + 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 +1538,14 @@ { PassManagerPrettyStackEntry X(FP, F); TimeRegion PassTimer(getPassTimer(FP)); +#ifndef NDEBUG + uint64_t RefHash = FunctionHash(F); +#endif LocalChanged |= FP->runOnFunction(F); + + assert(!LocalChanged && (RefHash != FunctionHash(F)) && + "Pass modifies its input and doesn't report it."); + if (EmitICRemark) { unsigned NewSize = F.getInstructionCount(); @@ -1580,7 +1646,15 @@ PassManagerPrettyStackEntry X(MP, M); TimeRegion PassTimer(getPassTimer(MP)); +#ifndef NDEBUG + uint64_t RefHash = ModuleHash(M); +#endif + LocalChanged |= MP->runOnModule(M); + + assert(!LocalChanged && (RefHash != ModuleHash(M)) && + "Pass modifies its input and doesn't report it."); + if (EmitICRemark) { // Update the size of the module. unsigned ModuleCount = M.getInstructionCount(); Index: llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -2421,7 +2421,7 @@ initializeCallbacks(M); if (CompileKernel) - return false; + return true; // because of the new callbacks added // Create a module constructor. A destructor is created lazily because not all // platforms, and not all modules need it. Index: llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -568,8 +568,9 @@ ExcludeRe = createRegexesFromString(Options.Exclude); if (Options.EmitNotes) emitProfileNotes(); - if (Options.EmitData) return emitProfileArcs(); - return false; + if (Options.EmitData) + emitProfileArcs(); + return true; // Because of the added flush. } PreservedAnalyses GCOVProfilerPass::run(Module &M,