Return "[NFC] Add severe validation of InstructionPrecedenceTracking"

This validation patch has been reverted as rL341147 because of conserns raised by
@reames. This revision returns it as is to raise a discussion and address the concerns.

Differential Revision: https://reviews.llvm.org/D51523
Reviewed By: reames

llvm-svn: 341526
This commit is contained in:
Max Kazantsev 2018-09-06 08:33:02 +00:00
parent d518c5fc87
commit 8a9e059e5c
2 changed files with 72 additions and 0 deletions

View File

@ -37,6 +37,18 @@ class InstructionPrecedenceTracking {
// Fills information about the given block's special instructions. // Fills information about the given block's special instructions.
void fill(const BasicBlock *BB); void fill(const BasicBlock *BB);
#ifndef NDEBUG
/// Asserts that the cached info for \p BB is up-to-date. This helps to catch
/// the usage error of accessing a block without properly invalidating after a
/// previous transform.
void validate(const BasicBlock *BB) const;
/// Asserts whether or not the contents of this tracking is up-to-date. This
/// helps to catch the usage error of accessing a block without properly
/// invalidating after a previous transform.
void validateAll() const;
#endif
protected: protected:
InstructionPrecedenceTracking(DominatorTree *DT) InstructionPrecedenceTracking(DominatorTree *DT)
: OI(OrderedInstructions(DT)) {} : OI(OrderedInstructions(DT)) {}

View File

@ -23,8 +23,25 @@
using namespace llvm; using namespace llvm;
#ifndef NDEBUG
static cl::opt<bool> ExpensiveAsserts(
"ipt-expensive-asserts",
cl::desc("Perform expensive assert validation on every query to Instruction"
" Precedence Tracking"),
cl::init(false), cl::Hidden);
#endif
const Instruction *InstructionPrecedenceTracking::getFirstSpecialInstruction( const Instruction *InstructionPrecedenceTracking::getFirstSpecialInstruction(
const BasicBlock *BB) { const BasicBlock *BB) {
#ifndef NDEBUG
// If there is a bug connected to invalid cache, turn on ExpensiveAsserts to
// catch this situation as early as possible.
if (ExpensiveAsserts)
validateAll();
else
validate(BB);
#endif
if (!KnownBlocks.count(BB)) if (!KnownBlocks.count(BB))
fill(BB); fill(BB);
auto *FirstICF = FirstSpecialInsts.lookup(BB); auto *FirstICF = FirstSpecialInsts.lookup(BB);
@ -56,6 +73,45 @@ void InstructionPrecedenceTracking::fill(const BasicBlock *BB) {
KnownBlocks.insert(BB); KnownBlocks.insert(BB);
} }
#ifndef NDEBUG
void InstructionPrecedenceTracking::validate(const BasicBlock *BB) const {
// If we don't know anything about this block, make sure we don't store
// a bucket for it in FirstSpecialInsts map.
if (!KnownBlocks.count(BB)) {
assert(FirstSpecialInsts.find(BB) == FirstSpecialInsts.end() && "Must be!");
return;
}
auto It = FirstSpecialInsts.find(BB);
bool BlockHasSpecialInsns = false;
for (const Instruction &Insn : *BB) {
if (isSpecialInstruction(&Insn)) {
assert(It != FirstSpecialInsts.end() &&
"Blocked marked as known but we have no cached value for it!");
assert(It->second == &Insn &&
"Cached first special instruction is wrong!");
BlockHasSpecialInsns = true;
break;
}
}
if (!BlockHasSpecialInsns)
assert(It == FirstSpecialInsts.end() &&
"Block is marked as having special instructions but in fact it "
"has none!");
}
void InstructionPrecedenceTracking::validateAll() const {
// Check that for every known block the cached value is correct.
for (auto *BB : KnownBlocks)
validate(BB);
// Check that all blocks with cached values are marked as known.
for (auto &It : FirstSpecialInsts)
assert(KnownBlocks.count(It.first) &&
"We have a cached value but the block is not marked as known?");
}
#endif
void InstructionPrecedenceTracking::invalidateBlock(const BasicBlock *BB) { void InstructionPrecedenceTracking::invalidateBlock(const BasicBlock *BB) {
OI.invalidateBlock(BB); OI.invalidateBlock(BB);
FirstSpecialInsts.erase(BB); FirstSpecialInsts.erase(BB);
@ -67,6 +123,10 @@ void InstructionPrecedenceTracking::clear() {
OI.invalidateBlock(It.first); OI.invalidateBlock(It.first);
FirstSpecialInsts.clear(); FirstSpecialInsts.clear();
KnownBlocks.clear(); KnownBlocks.clear();
#ifndef NDEBUG
// The map should be valid after clearing (at least empty).
validateAll();
#endif
} }
bool ImplicitControlFlowTracking::isSpecialInstruction( bool ImplicitControlFlowTracking::isSpecialInstruction(