[MemorySSA] Add verification levels to MemorySSA. [NFC]

Add two levels of verification for MemorySSA: Fast and Full.
The defaults are kept the same. Full verification always occurs under
EXPENSIVE_CHECKS, but now it can also be requested in a specific pass for
debugging purposes.
This commit is contained in:
Alina Sbirlea 2021-09-15 10:53:35 -07:00
parent 13237c3b1e
commit b759381b75
2 changed files with 29 additions and 28 deletions

View File

@ -783,9 +783,10 @@ public:
/// dominates Use \p B.
bool dominates(const MemoryAccess *A, const Use &B) const;
enum class VerificationLevel { Fast, Full };
/// Verify that MemorySSA is self consistent (IE definitions dominate
/// all uses, uses appear in the right places). This is used by unit tests.
void verifyMemorySSA() const;
void verifyMemorySSA(VerificationLevel = VerificationLevel::Fast) const;
/// Used in various insertion functions to specify whether we are talking
/// about the beginning or end of a block.
@ -796,7 +797,8 @@ protected:
friend class MemorySSAPrinterLegacyPass;
friend class MemorySSAUpdater;
void verifyOrderingDominationAndDefUses(Function &F) const;
void verifyOrderingDominationAndDefUses(
Function &F, VerificationLevel = VerificationLevel::Fast) const;
void verifyDominationNumbers(const Function &F) const;
void verifyPrevDefInPhis(Function &F) const;

View File

@ -1896,10 +1896,17 @@ void MemorySSA::print(raw_ostream &OS) const {
LLVM_DUMP_METHOD void MemorySSA::dump() const { print(dbgs()); }
#endif
void MemorySSA::verifyMemorySSA() const {
verifyOrderingDominationAndDefUses(F);
void MemorySSA::verifyMemorySSA(VerificationLevel VL) const {
#if !defined(NDEBUG) && defined(EXPENSIVE_CHECKS)
VL = VerificationLevel::Full;
#endif
#ifndef NDEBUG
verifyOrderingDominationAndDefUses(F, VL);
verifyDominationNumbers(F);
verifyPrevDefInPhis(F);
if (VL == VerificationLevel::Full)
verifyPrevDefInPhis(F);
#endif
// Previously, the verification used to also verify that the clobberingAccess
// cached by MemorySSA is the same as the clobberingAccess found at a later
// query to AA. This does not hold true in general due to the current fragility
@ -1913,7 +1920,6 @@ void MemorySSA::verifyMemorySSA() const {
}
void MemorySSA::verifyPrevDefInPhis(Function &F) const {
#if !defined(NDEBUG) && defined(EXPENSIVE_CHECKS)
for (const BasicBlock &BB : F) {
if (MemoryPhi *Phi = getMemoryAccess(&BB)) {
for (unsigned I = 0, E = Phi->getNumIncomingValues(); I != E; ++I) {
@ -1943,13 +1949,11 @@ void MemorySSA::verifyPrevDefInPhis(Function &F) const {
}
}
}
#endif
}
/// Verify that all of the blocks we believe to have valid domination numbers
/// actually have valid domination numbers.
void MemorySSA::verifyDominationNumbers(const Function &F) const {
#ifndef NDEBUG
if (BlockNumberingValid.empty())
return;
@ -1981,7 +1985,6 @@ void MemorySSA::verifyDominationNumbers(const Function &F) const {
assert(ValidBlocks.empty() &&
"All valid BasicBlocks should exist in F -- dangling pointers?");
#endif
}
/// Verify ordering: the order and existence of MemoryAccesses matches the
@ -1990,8 +1993,8 @@ void MemorySSA::verifyDominationNumbers(const Function &F) const {
/// Verify def-uses: the immediate use information - walk all the memory
/// accesses and verifying that, for each use, it appears in the appropriate
/// def's use list
void MemorySSA::verifyOrderingDominationAndDefUses(Function &F) const {
#if !defined(NDEBUG)
void MemorySSA::verifyOrderingDominationAndDefUses(Function &F,
VerificationLevel VL) const {
// Walk all the blocks, comparing what the lookups think and what the access
// lists think, as well as the order in the blocks vs the order in the access
// lists.
@ -2008,17 +2011,17 @@ void MemorySSA::verifyOrderingDominationAndDefUses(Function &F) const {
// Verify domination
for (const Use &U : Phi->uses())
assert(dominates(Phi, U) && "Memory PHI does not dominate it's uses");
#if defined(EXPENSIVE_CHECKS)
// Verify def-uses.
assert(Phi->getNumOperands() == static_cast<unsigned>(std::distance(
pred_begin(&B), pred_end(&B))) &&
"Incomplete MemoryPhi Node");
for (unsigned I = 0, E = Phi->getNumIncomingValues(); I != E; ++I) {
verifyUseInDefs(Phi->getIncomingValue(I), Phi);
assert(is_contained(predecessors(&B), Phi->getIncomingBlock(I)) &&
"Incoming phi block not a block predecessor");
// Verify def-uses for full verify.
if (VL == VerificationLevel::Full) {
assert(Phi->getNumOperands() == static_cast<unsigned>(std::distance(
pred_begin(&B), pred_end(&B))) &&
"Incomplete MemoryPhi Node");
for (unsigned I = 0, E = Phi->getNumIncomingValues(); I != E; ++I) {
verifyUseInDefs(Phi->getIncomingValue(I), Phi);
assert(is_contained(predecessors(&B), Phi->getIncomingBlock(I)) &&
"Incoming phi block not a block predecessor");
}
}
#endif
}
for (Instruction &I : B) {
@ -2038,10 +2041,9 @@ void MemorySSA::verifyOrderingDominationAndDefUses(Function &F) const {
assert(dominates(MD, U) &&
"Memory Def does not dominate it's uses");
}
#if defined(EXPENSIVE_CHECKS)
// Verify def-uses.
verifyUseInDefs(MA->getDefiningAccess(), MA);
#endif
// Verify def-uses for full verify.
if (VL == VerificationLevel::Full)
verifyUseInDefs(MA->getDefiningAccess(), MA);
}
}
// Either we hit the assert, really have no accesses, or we have both
@ -2076,13 +2078,11 @@ void MemorySSA::verifyOrderingDominationAndDefUses(Function &F) const {
}
ActualDefs.clear();
}
#endif
}
/// Verify the def-use lists in MemorySSA, by verifying that \p Use
/// appears in the use list of \p Def.
void MemorySSA::verifyUseInDefs(MemoryAccess *Def, MemoryAccess *Use) const {
#ifndef NDEBUG
// The live on entry use may cause us to get a NULL def here
if (!Def)
assert(isLiveOnEntryDef(Use) &&
@ -2090,7 +2090,6 @@ void MemorySSA::verifyUseInDefs(MemoryAccess *Def, MemoryAccess *Use) const {
else
assert(is_contained(Def->users(), Use) &&
"Did not find use in def's use list");
#endif
}
/// Perform a local numbering on blocks so that instruction ordering can be