mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[MemorySSA] Combine verifications.
Summary: Combine three verification methods into one to improve compile time when asserts are enabled. Motivated by PR44066. Sample change of timings on testcase in PR44066 (release+asserts): MSSA off or verification disabled: 1.13s. MSSA on (ToT): 2.48s. With patch: 2.03s. With enabling DefUses after combining Domination+Ordering: 2.6s. After also combining DefUses with Domination+Ordering: 2.06s (candidate to be taken out of EXPENSIVE_CHECKS). Subscribers: Prazek, hiraditya, george.burgess.iv, sanjoy.google, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D70618
This commit is contained in:
parent
610b3b73a9
commit
61f1e80d57
@ -794,11 +794,9 @@ protected:
|
||||
friend class MemorySSAPrinterLegacyPass;
|
||||
friend class MemorySSAUpdater;
|
||||
|
||||
void verifyPrevDefInPhis(Function &F) const;
|
||||
void verifyDefUses(Function &F) const;
|
||||
void verifyDomination(Function &F) const;
|
||||
void verifyOrdering(Function &F) const;
|
||||
void verifyOrderingDominationAndDefUses(Function &F) const;
|
||||
void verifyDominationNumbers(const Function &F) const;
|
||||
void verifyPrevDefInPhis(Function &F) const;
|
||||
|
||||
// This is used by the use optimizer and updater.
|
||||
AccessList *getWritableBlockAccesses(const BasicBlock *BB) const {
|
||||
|
@ -1870,9 +1870,7 @@ LLVM_DUMP_METHOD void MemorySSA::dump() const { print(dbgs()); }
|
||||
#endif
|
||||
|
||||
void MemorySSA::verifyMemorySSA() const {
|
||||
verifyDefUses(F);
|
||||
verifyDomination(F);
|
||||
verifyOrdering(F);
|
||||
verifyOrderingDominationAndDefUses(F);
|
||||
verifyDominationNumbers(F);
|
||||
verifyPrevDefInPhis(F);
|
||||
// Previously, the verification used to also verify that the clobberingAccess
|
||||
@ -1959,10 +1957,14 @@ void MemorySSA::verifyDominationNumbers(const Function &F) const {
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Verify that the order and existence of MemoryAccesses matches the
|
||||
/// Verify ordering: the order and existence of MemoryAccesses matches the
|
||||
/// order and existence of memory affecting instructions.
|
||||
void MemorySSA::verifyOrdering(Function &F) const {
|
||||
#ifndef NDEBUG
|
||||
/// Verify domination: each definition dominates all of its uses.
|
||||
/// 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)
|
||||
// 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.
|
||||
@ -1971,29 +1973,56 @@ void MemorySSA::verifyOrdering(Function &F) const {
|
||||
for (BasicBlock &B : F) {
|
||||
const AccessList *AL = getBlockAccesses(&B);
|
||||
const auto *DL = getBlockDefs(&B);
|
||||
MemoryAccess *Phi = getMemoryAccess(&B);
|
||||
MemoryPhi *Phi = getMemoryAccess(&B);
|
||||
if (Phi) {
|
||||
// Verify ordering.
|
||||
ActualAccesses.push_back(Phi);
|
||||
ActualDefs.push_back(Phi);
|
||||
// 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(find(predecessors(&B), Phi->getIncomingBlock(I)) !=
|
||||
pred_end(&B) &&
|
||||
"Incoming phi block not a block predecessor");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for (Instruction &I : B) {
|
||||
MemoryAccess *MA = getMemoryAccess(&I);
|
||||
MemoryUseOrDef *MA = getMemoryAccess(&I);
|
||||
assert((!MA || (AL && (isa<MemoryUse>(MA) || DL))) &&
|
||||
"We have memory affecting instructions "
|
||||
"in this block but they are not in the "
|
||||
"access list or defs list");
|
||||
if (MA) {
|
||||
// Verify ordering.
|
||||
ActualAccesses.push_back(MA);
|
||||
if (isa<MemoryDef>(MA))
|
||||
if (MemoryAccess *MD = dyn_cast<MemoryDef>(MA)) {
|
||||
// Verify ordering.
|
||||
ActualDefs.push_back(MA);
|
||||
// Verify domination.
|
||||
for (const Use &U : MD->uses())
|
||||
assert(dominates(MD, U) &&
|
||||
"Memory Def does not dominate it's uses");
|
||||
}
|
||||
#if defined(EXPENSIVE_CHECKS)
|
||||
// Verify def-uses.
|
||||
verifyUseInDefs(MA->getDefiningAccess(), MA);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// Either we hit the assert, really have no accesses, or we have both
|
||||
// accesses and an access list.
|
||||
// Same with defs.
|
||||
// accesses and an access list. Same with defs.
|
||||
if (!AL && !DL)
|
||||
continue;
|
||||
// Verify ordering.
|
||||
assert(AL->size() == ActualAccesses.size() &&
|
||||
"We don't have the same number of accesses in the block as on the "
|
||||
"access list");
|
||||
@ -2024,28 +2053,6 @@ void MemorySSA::verifyOrdering(Function &F) const {
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Verify the domination properties of MemorySSA by checking that each
|
||||
/// definition dominates all of its uses.
|
||||
void MemorySSA::verifyDomination(Function &F) const {
|
||||
#ifndef NDEBUG
|
||||
for (BasicBlock &B : F) {
|
||||
// Phi nodes are attached to basic blocks
|
||||
if (MemoryPhi *MP = getMemoryAccess(&B))
|
||||
for (const Use &U : MP->uses())
|
||||
assert(dominates(MP, U) && "Memory PHI does not dominate it's uses");
|
||||
|
||||
for (Instruction &I : B) {
|
||||
MemoryAccess *MD = dyn_cast_or_null<MemoryDef>(getMemoryAccess(&I));
|
||||
if (!MD)
|
||||
continue;
|
||||
|
||||
for (const Use &U : MD->uses())
|
||||
assert(dominates(MD, U) && "Memory Def does not dominate it's uses");
|
||||
}
|
||||
}
|
||||
#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 {
|
||||
@ -2060,34 +2067,6 @@ void MemorySSA::verifyUseInDefs(MemoryAccess *Def, MemoryAccess *Use) const {
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Verify the immediate use information, by walking all the memory
|
||||
/// accesses and verifying that, for each use, it appears in the
|
||||
/// appropriate def's use list
|
||||
void MemorySSA::verifyDefUses(Function &F) const {
|
||||
#if !defined(NDEBUG) && defined(EXPENSIVE_CHECKS)
|
||||
for (BasicBlock &B : F) {
|
||||
// Phi nodes are attached to basic blocks
|
||||
if (MemoryPhi *Phi = getMemoryAccess(&B)) {
|
||||
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(find(predecessors(&B), Phi->getIncomingBlock(I)) !=
|
||||
pred_end(&B) &&
|
||||
"Incoming phi block not a block predecessor");
|
||||
}
|
||||
}
|
||||
|
||||
for (Instruction &I : B) {
|
||||
if (MemoryUseOrDef *MA = getMemoryAccess(&I)) {
|
||||
verifyUseInDefs(MA->getDefiningAccess(), MA);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Perform a local numbering on blocks so that instruction ordering can be
|
||||
/// determined in constant time.
|
||||
/// TODO: We currently just number in order. If we numbered by N, we could
|
||||
|
Loading…
Reference in New Issue
Block a user