Skip to content

Commit a4dba76

Browse files
dcciDavide Italiano
authored andcommitted
[DebugInfo] Add a verifier pass to find holes in lexical scopes.
This found a bunch of issues where we didn't properly preserve debug infos which have been fixed over the course of the past two weeks. The basic idea is we want to make sure that within a BB we never have `holes` in debug scopes, i.e. if we enter a scope, one of the two holds 1) We never visited that scope before 2) We're re-entering a scope that is an ancestor of the scope currently leaving. This is needed to correctly model nested scopes, e.g. { let i = 0; // scope 0 if (cond) { let j = i // scope 1 } let k = i + 1 // scope 0 and okay. } I also checked in a `cl::opt`, so that if this breaks something, it can be conveniently disabled. This is currently not enabled as we flesh out the last violations. <rdar://problem/35816212>
1 parent 0665e21 commit a4dba76

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed

lib/SIL/SILVerifier.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ static llvm::cl::opt<bool> AbortOnFailure(
5656
"verify-abort-on-failure",
5757
llvm::cl::init(true));
5858

59+
static llvm::cl::opt<bool> VerifyDIHoles(
60+
"verify-di-holes",
61+
llvm::cl::init(false));
62+
5963
// The verifier is basically all assertions, so don't compile it with NDEBUG to
6064
// prevent release builds from triggering spurious unused variable warnings.
6165

@@ -4338,6 +4342,78 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
43384342
}
43394343
}
43404344

4345+
/// This pass verifies that there are no hole in debug scopes at -Onone.
4346+
void verifyDebugScopeHoles(SILBasicBlock *BB) {
4347+
if (!VerifyDIHoles)
4348+
return;
4349+
4350+
// This check only makes sense at -Onone. Optimizations,
4351+
// e.g. inlining, can move scopes around.
4352+
llvm::DenseSet<const SILDebugScope *> AlreadySeenScopes;
4353+
if (BB->getParent()->getEffectiveOptimizationMode() !=
4354+
OptimizationMode::NoOptimization)
4355+
return;
4356+
4357+
// Exit early if this BB is empty.
4358+
if (BB->empty())
4359+
return;
4360+
4361+
const SILDebugScope *LastSeenScope = nullptr;
4362+
for (SILInstruction &SI : *BB) {
4363+
if (isa<AllocStackInst>(SI))
4364+
continue;
4365+
LastSeenScope = SI.getDebugScope();
4366+
AlreadySeenScopes.insert(LastSeenScope);
4367+
break;
4368+
}
4369+
for (SILInstruction &SI : *BB) {
4370+
// `alloc_stack` can create false positive, so we skip it
4371+
// for now.
4372+
if (isa<AllocStackInst>(SI))
4373+
continue;
4374+
4375+
// If we haven't seen this debug scope yet, update the
4376+
// map and go on.
4377+
auto *DS = SI.getDebugScope();
4378+
assert(DS && "Each instruction should have a debug scope");
4379+
if (!AlreadySeenScopes.count(DS)) {
4380+
AlreadySeenScopes.insert(DS);
4381+
LastSeenScope = DS;
4382+
continue;
4383+
}
4384+
4385+
// Otherwise, we're allowed to re-enter a scope only if
4386+
// the scope is an ancestor of the scope we're currently leaving.
4387+
auto isAncestorScope = [](const SILDebugScope *Cur,
4388+
const SILDebugScope *Previous) {
4389+
const SILDebugScope *Tmp = Previous;
4390+
assert(Tmp && "scope can't be null");
4391+
while (Tmp) {
4392+
PointerUnion<const SILDebugScope *, SILFunction *> Parent =
4393+
Tmp->Parent;
4394+
auto *ParentScope = Parent.dyn_cast<const SILDebugScope *>();
4395+
if (!ParentScope)
4396+
break;
4397+
if (ParentScope == Cur)
4398+
return true;
4399+
Tmp = ParentScope;
4400+
}
4401+
return false;
4402+
};
4403+
4404+
if (isAncestorScope(DS, LastSeenScope)) {
4405+
LastSeenScope = DS;
4406+
continue;
4407+
}
4408+
if (DS != LastSeenScope) {
4409+
DEBUG(llvm::dbgs() << "Broken instruction!\n"; SI.dump());
4410+
require(
4411+
DS == LastSeenScope,
4412+
"Basic block contains a non-contiguous lexical scope at -Onone");
4413+
}
4414+
}
4415+
}
4416+
43414417
void visitSILBasicBlock(SILBasicBlock *BB) {
43424418
// Make sure that each of the successors/predecessors of this basic block
43434419
// have this basic block in its predecessor/successor list.
@@ -4360,6 +4436,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
43604436
}
43614437

43624438
SILInstructionVisitor::visitSILBasicBlock(BB);
4439+
verifyDebugScopeHoles(BB);
43634440
}
43644441

43654442
void visitBasicBlockArguments(SILBasicBlock *BB) {

0 commit comments

Comments
 (0)