Skip to content

Commit cffcd9a

Browse files
authored
Merge pull request #35333 from slavapestov/debug-scope-guard-stmt-5.4
SILGen: Introduce a new debug scope for GuardStmts [5.4]
2 parents 4070b4f + e9d557a commit cffcd9a

File tree

4 files changed

+74
-26
lines changed

4 files changed

+74
-26
lines changed

lib/SILGen/SILGenFunction.h

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
329329
std::vector<BreakContinueDest> BreakContinueDestStack;
330330
std::vector<PatternMatchContext*> SwitchStack;
331331
/// Keep track of our current nested scope.
332-
std::vector<const SILDebugScope *> DebugScopeStack;
332+
///
333+
/// The boolean tracks whether this is a 'guard' scope, which should be
334+
/// popped automatically when we leave the innermost BraceStmt scope.
335+
std::vector<llvm::PointerIntPair<const SILDebugScope *, 1>> DebugScopeStack;
333336

334337
/// The cleanup depth and BB for when the operand of a
335338
/// BindOptionalExpr is a missing value.
@@ -590,23 +593,32 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
590593
StringRef getMagicFunctionString();
591594

592595
/// Enter the debug scope for \p Loc, creating it if necessary.
593-
void enterDebugScope(SILLocation Loc) {
596+
///
597+
/// \param isGuardScope If true, this is a scope for the bindings introduced by
598+
/// a 'guard' statement. This scope ends when the next innermost BraceStmt ends.
599+
void enterDebugScope(SILLocation Loc, bool isGuardScope=false) {
594600
auto *Parent =
595-
DebugScopeStack.size() ? DebugScopeStack.back() : F.getDebugScope();
601+
DebugScopeStack.size() ? DebugScopeStack.back().getPointer() : F.getDebugScope();
596602
auto *DS = Parent;
597603
// Don't nest a scope for Loc under Parent unless it's actually different.
598-
if (Parent->getLoc().getAsRegularLocation() != Loc.getAsRegularLocation())
599-
DS = DS = new (SGM.M)
600-
SILDebugScope(Loc.getAsRegularLocation(), &getFunction(), Parent);
601-
DebugScopeStack.push_back(DS);
604+
if (DS->getLoc().getAsRegularLocation() != Loc.getAsRegularLocation()) {
605+
DS = new (SGM.M)
606+
SILDebugScope(Loc.getAsRegularLocation(), &getFunction(), DS);
607+
}
608+
DebugScopeStack.emplace_back(DS, isGuardScope);
602609
B.setCurrentDebugScope(DS);
603610
}
604611

605612
/// Return to the previous debug scope.
606613
void leaveDebugScope() {
614+
// Pop any 'guard' scopes first.
615+
while (DebugScopeStack.back().getInt())
616+
DebugScopeStack.pop_back();
617+
618+
// Pop the scope we're leaving now.
607619
DebugScopeStack.pop_back();
608620
if (DebugScopeStack.size())
609-
B.setCurrentDebugScope(DebugScopeStack.back());
621+
B.setCurrentDebugScope(DebugScopeStack.back().getPointer());
610622
// Don't reset the debug scope after leaving the outermost scope,
611623
// because the debugger is not expecting the function epilogue to
612624
// be in a different scope.

lib/SILGen/SILGenStmt.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -724,11 +724,14 @@ void StmtEmitter::visitGuardStmt(GuardStmt *S) {
724724
SGF.B.createUnreachable(S);
725725
}
726726

727-
// Emit the condition bindings, branching to the bodyBB if they fail. Since
728-
// we didn't push a scope, the bound variables are live after this statement.
727+
// Emit the condition bindings, branching to the bodyBB if they fail.
729728
auto NumFalseTaken = SGF.loadProfilerCount(S->getBody());
730729
auto NumNonTaken = SGF.loadProfilerCount(S);
731730
SGF.emitStmtCondition(S->getCond(), bodyBB, S, NumNonTaken, NumFalseTaken);
731+
732+
// Begin a new 'guard' scope, which is popped when the next innermost debug
733+
// scope ends.
734+
SGF.enterDebugScope(S, /*isGuardScope=*/true);
732735
}
733736

734737
void StmtEmitter::visitWhileStmt(WhileStmt *S) {

test/DebugInfo/guard-let.swift

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,19 @@
22
// RUN: %FileCheck %s --check-prefix=CHECK1
33
// RUN: %target-swift-frontend %s -c -emit-ir -g -o - | \
44
// RUN: %FileCheck %s --check-prefix=CHECK2
5+
// RUN: %target-swift-frontend %s -c -emit-ir -g -o - | \
6+
// RUN: %FileCheck %s --check-prefix=CHECK3
57

68
// UNSUPPORTED: OS=watchos
79

10+
// With large type optimizations the string is passed indirectly on the
11+
// following architectures so there is no shadow copy happening. As this
12+
// tests that we're emitting the DI correctly, we can skip running on them.
13+
// UNSUPPORTED: CPU=i386
14+
// UNSUPPORTED: CPU=armv7
15+
// UNSUPPORTED: CPU=armv7s
16+
// UNSUPPORTED: CPU=armv7k
17+
818
func use<T>(_ t: T) {}
919

1020
public func f(_ i : Int?)
@@ -25,14 +35,6 @@ public func f(_ i : Int?)
2535
use(val)
2636
}
2737

28-
// With large type optimizations the string is passed indirectly on the
29-
// following architectures so there is no shadow copy happening. As this
30-
// tests that we're emitting the DI correctly, we can skip running on them.
31-
// UNSUPPORTED: CPU=i386
32-
// UNSUPPORTED: CPU=armv7
33-
// UNSUPPORTED: CPU=armv7s
34-
// UNSUPPORTED: CPU=armv7k
35-
3638
public func g(_ s : String?)
3739
{
3840
// CHECK2: define {{.*}}@"$s4main1gyySSSgF"
@@ -46,3 +48,32 @@ public func g(_ s : String?)
4648
guard let val = s else { return }
4749
use(val)
4850
}
51+
52+
public func h(_ s : String?)
53+
{
54+
// CHECK3: define {{.*}}@"$s4main1hyySSSgF"
55+
// CHECK3: %s.debug = alloca %TSSSg
56+
// CHECK3: @llvm.dbg.declare(metadata %TSSSg*
57+
// CHECK3: %s.debug1 = alloca %TSS
58+
// CHECK3: @llvm.dbg.declare(metadata %TSS*
59+
// CHECK3: %[[BITCAST:.*]] = bitcast %TSS* %s.debug1 to i8*{{$}}
60+
// CHECK3: call void @llvm.memset.{{.*}}(i8* align {{(4|8)}} %[[BITCAST]], i8 0
61+
// CHECK3: ![[G:.*]] = distinct !DISubprogram(name: "h"
62+
guard let s = s else { return }
63+
use(s)
64+
}
65+
66+
enum MyError : Error {
67+
case bad
68+
}
69+
70+
enum Stuff {
71+
case array([Stuff])
72+
case any(Any)
73+
case nothing
74+
75+
func toArray() throws -> [Stuff] {
76+
guard case .array(let array) = self else { throw MyError.bad }
77+
return array
78+
}
79+
}

test/SILOptimizer/definite-init-wrongscope.swift

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,16 @@ public class M {
2828

2929
// Make sure the expanded sequence gets the right scope.
3030

31-
// CHECK: [[I:%.*]] = integer_literal $Builtin.Int2, 1, loc {{.*}}:20:12, scope 2
32-
// CHECK: [[V:%.*]] = load [trivial] %2 : $*Builtin.Int2, loc {{.*}}:20:12, scope 2
33-
// CHECK: [[OR:%.*]] = builtin "or_Int2"([[V]] : $Builtin.Int2, [[I]] : $Builtin.Int2) : $Builtin.Int2, loc {{.*}}:20:12, scope 2
34-
// CHECK: store [[OR]] to [trivial] %2 : $*Builtin.Int2, loc {{.*}}:20:12, scope 2
35-
// CHECK: store %{{.*}} to [init] %{{.*}} : $*C, loc {{.*}}:23:20, scope 2
31+
// CHECK-LABEL: sil [ossa] @$s3del1MC4fromAcA12WithDelegate_p_tKcfc : $@convention(method) (@in WithDelegate, @owned M) -> (@owned M, @error Error)
32+
33+
// CHECK: [[I:%.*]] = integer_literal $Builtin.Int2, 1, loc {{.*}}:20:12, scope 4
34+
// CHECK: [[V:%.*]] = load [trivial] %2 : $*Builtin.Int2, loc {{.*}}:20:12, scope 4
35+
// CHECK: [[OR:%.*]] = builtin "or_Int2"([[V]] : $Builtin.Int2, [[I]] : $Builtin.Int2) : $Builtin.Int2, loc {{.*}}:20:12, scope 4
36+
// CHECK: store [[OR]] to [trivial] %2 : $*Builtin.Int2, loc {{.*}}:20:12, scope 4
37+
// CHECK: store %{{.*}} to [init] %{{.*}} : $*C, loc {{.*}}:23:20, scope 4
3638

3739
// Make sure the dealloc_stack gets the same scope of the instructions surrounding it.
3840

39-
// CHECK: destroy_addr %0 : $*WithDelegate, loc {{.*}}:26:5, scope 2
40-
// CHECK: dealloc_stack %2 : $*Builtin.Int2, loc {{.*}}:20:12, scope 2
41-
// CHECK: throw %{{.*}} : $Error, loc {{.*}}:20:12, scope 2
41+
// CHECK: destroy_addr %0 : $*WithDelegate, loc {{.*}}:26:5, scope 4
42+
// CHECK: dealloc_stack %2 : $*Builtin.Int2, loc {{.*}}:20:12, scope 4
43+
// CHECK: throw %{{.*}} : $Error, loc {{.*}}:20:12, scope 4

0 commit comments

Comments
 (0)