Please use GitHub pull requests for new patches. Phabricator shutdown timeline
Changeset View
Standalone View
llvm/lib/Passes/StandardInstrumentations.cpp
Show First 20 Lines • Show All 1,061 Lines • ▼ Show 20 Lines | struct PreservedFunctionHashAnalysis | ||||
Result run(Function &F, FunctionAnalysisManager &FAM) { | Result run(Function &F, FunctionAnalysisManager &FAM) { | ||||
return Result{StructuralHash(F)}; | return Result{StructuralHash(F)}; | ||||
} | } | ||||
}; | }; | ||||
AnalysisKey PreservedFunctionHashAnalysis::Key; | AnalysisKey PreservedFunctionHashAnalysis::Key; | ||||
struct PreservedModuleHashAnalysis | |||||
: public AnalysisInfoMixin<PreservedModuleHashAnalysis> { | |||||
static AnalysisKey Key; | |||||
struct ModuleHash { | |||||
uint64_t Hash; | |||||
}; | |||||
using Result = ModuleHash; | |||||
Result run(Module &F, ModuleAnalysisManager &FAM) { | |||||
return Result{StructuralHash(F)}; | |||||
} | |||||
}; | |||||
AnalysisKey PreservedModuleHashAnalysis::Key; | |||||
bool PreservedCFGCheckerInstrumentation::CFG::invalidate( | bool PreservedCFGCheckerInstrumentation::CFG::invalidate( | ||||
Function &F, const PreservedAnalyses &PA, | Function &F, const PreservedAnalyses &PA, | ||||
FunctionAnalysisManager::Invalidator &) { | FunctionAnalysisManager::Invalidator &) { | ||||
auto PAC = PA.getChecker<PreservedCFGCheckerAnalysis>(); | auto PAC = PA.getChecker<PreservedCFGCheckerAnalysis>(); | ||||
return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>() || | return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>() || | ||||
PAC.preservedSet<CFGAnalyses>()); | PAC.preservedSet<CFGAnalyses>()); | ||||
} | } | ||||
Show All 23 Lines | #endif | ||||
(void)this; | (void)this; | ||||
auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>( | auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>( | ||||
*const_cast<Module *>(unwrapModule(IR, /*Force=*/true))) | *const_cast<Module *>(unwrapModule(IR, /*Force=*/true))) | ||||
.getManager(); | .getManager(); | ||||
if (!Registered) { | if (!Registered) { | ||||
FAM.registerPass([&] { return PreservedCFGCheckerAnalysis(); }); | FAM.registerPass([&] { return PreservedCFGCheckerAnalysis(); }); | ||||
FAM.registerPass([&] { return PreservedFunctionHashAnalysis(); }); | FAM.registerPass([&] { return PreservedFunctionHashAnalysis(); }); | ||||
MAM.registerPass([&] { return PreservedModuleHashAnalysis(); }); | |||||
nikic: Do this outside the pass callback? | |||||
might as well be consistent with the FAM code, which requires having some IR to get from the MAM (or we coul pass in the FAM, but that's more work for callers) aeubanks: might as well be consistent with the `FAM` code, which requires having some IR to get from the… | |||||
Registered = true; | Registered = true; | ||||
} | } | ||||
for (Function *F : GetFunctions(IR)) { | for (Function *F : GetFunctions(IR)) { | ||||
// Make sure a fresh CFG snapshot is available before the pass. | // Make sure a fresh CFG snapshot is available before the pass. | ||||
FAM.getResult<PreservedCFGCheckerAnalysis>(*F); | FAM.getResult<PreservedCFGCheckerAnalysis>(*F); | ||||
FAM.getResult<PreservedFunctionHashAnalysis>(*F); | FAM.getResult<PreservedFunctionHashAnalysis>(*F); | ||||
} | } | ||||
if (auto *MaybeM = any_cast<const Module *>(&IR)) { | |||||
Module &M = **const_cast<Module **>(MaybeM); | |||||
MAM.getResult<PreservedModuleHashAnalysis>(M); | |||||
} | |||||
}); | }); | ||||
PIC.registerAfterPassInvalidatedCallback( | PIC.registerAfterPassInvalidatedCallback( | ||||
[this](StringRef P, const PreservedAnalyses &PassPA) { | [this](StringRef P, const PreservedAnalyses &PassPA) { | ||||
#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS | #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS | ||||
assert(PassStack.pop_back_val() == P && | assert(PassStack.pop_back_val() == P && | ||||
"Before and After callbacks must correspond"); | "Before and After callbacks must correspond"); | ||||
#endif | #endif | ||||
Show All 39 Lines | for (Function *F : GetFunctions(IR)) { | ||||
report_fatal_error(Twine("CFG unexpectedly changed by ", Pass)); | report_fatal_error(Twine("CFG unexpectedly changed by ", Pass)); | ||||
}; | }; | ||||
if (auto *GraphBefore = | if (auto *GraphBefore = | ||||
FAM.getCachedResult<PreservedCFGCheckerAnalysis>(*F)) | FAM.getCachedResult<PreservedCFGCheckerAnalysis>(*F)) | ||||
CheckCFG(P, F->getName(), *GraphBefore, | CheckCFG(P, F->getName(), *GraphBefore, | ||||
CFG(F, /* TrackBBLifetime */ false)); | CFG(F, /* TrackBBLifetime */ false)); | ||||
} | } | ||||
if (auto *MaybeM = any_cast<const Module *>(&IR)) { | |||||
Module &M = **const_cast<Module **>(MaybeM); | |||||
if (auto *HashBefore = | |||||
MAM.getCachedResult<PreservedModuleHashAnalysis>(M)) { | |||||
if (HashBefore->Hash != StructuralHash(M)) { | |||||
report_fatal_error(formatv( | |||||
"Module changed by {0} without invalidating analyses", P)); | |||||
} | |||||
} | |||||
} | |||||
Not Done ReplyInline ActionsHm, does that mean that in most cases we're going to verify both all functions via the function hash, and then again using the module hash (which includes all function hashes)? nikic: Hm, does that mean that in most cases we're going to verify both all functions via the function… | |||||
yes, but that's fine, it's only doubling this work (which shouldn't matter in expensive checks builds) we could have the module analysis fetch the hash of each function via the function hash analysis, but at that point we start mixing module and function analyses which I'd like to avoid to keep this conceptually simple and not fall into traps with cross-level analyses (and it would require changes of how we hash modules by combining function hashes rather than hashing everything one after the other, but that's not too much work) aeubanks: yes, but that's fine, it's only doubling this work (which shouldn't matter in expensive checks… | |||||
Not Done ReplyInline ActionsOkay, let's keep it simple for now... nikic: Okay, let's keep it simple for now... | |||||
}); | }); | ||||
} | } | ||||
void VerifyInstrumentation::registerCallbacks( | void VerifyInstrumentation::registerCallbacks( | ||||
PassInstrumentationCallbacks &PIC) { | PassInstrumentationCallbacks &PIC) { | ||||
PIC.registerAfterPassCallback( | PIC.registerAfterPassCallback( | ||||
[this](StringRef P, Any IR, const PreservedAnalyses &PassPA) { | [this](StringRef P, Any IR, const PreservedAnalyses &PassPA) { | ||||
if (isIgnored(P) || P == "VerifierPass") | if (isIgnored(P) || P == "VerifierPass") | ||||
▲ Show 20 Lines • Show All 1,058 Lines • Show Last 20 Lines |
Do this outside the pass callback?