Skip to content

Commit 51f75c9

Browse files
committed
MoveOnlyAddressChecker: Reintroduce debug info for variables after reassignment.
After a value is consumed, we emit a `debug_value undef` to indicate that the variable value is no longer valid to the debugger. However, once a value is reassigned, it becomes valid again, so emit a `debug_value %original_address` to reassociate the variable with the valid memory location. rdar://109218404
1 parent 73df9f2 commit 51f75c9

File tree

4 files changed

+103
-40
lines changed

4 files changed

+103
-40
lines changed

include/swift/SIL/DebugUtils.h

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -534,29 +534,6 @@ struct DebugVarCarryingInst : VarDeclCarryingInst {
534534
}
535535
};
536536

537-
inline DebugVarCarryingInst DebugVarCarryingInst::getFromValue(SILValue value) {
538-
if (auto *svi = dyn_cast<SingleValueInstruction>(value)) {
539-
if (auto result = VarDeclCarryingInst(svi)) {
540-
switch (result.getKind()) {
541-
case VarDeclCarryingInst::Kind::Invalid:
542-
llvm_unreachable("ShouldKind have never seen this");
543-
case VarDeclCarryingInst::Kind::DebugValue:
544-
case VarDeclCarryingInst::Kind::AllocStack:
545-
case VarDeclCarryingInst::Kind::AllocBox:
546-
return DebugVarCarryingInst(svi);
547-
case VarDeclCarryingInst::Kind::GlobalAddr:
548-
case VarDeclCarryingInst::Kind::RefElementAddr:
549-
return DebugVarCarryingInst();
550-
}
551-
}
552-
}
553-
554-
if (auto *use = getSingleDebugUse(value))
555-
return DebugVarCarryingInst(use->getUser());
556-
557-
return DebugVarCarryingInst();
558-
}
559-
560537
static_assert(sizeof(DebugVarCarryingInst) == sizeof(VarDeclCarryingInst) &&
561538
alignof(DebugVarCarryingInst) == alignof(VarDeclCarryingInst),
562539
"Expected debug var carrying inst to have the same "

lib/SIL/Utils/DebugUtils.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,26 @@ bool swift::hasNonTrivialNonDebugTransitiveUsers(
6464
}
6565
return false;
6666
}
67+
68+
DebugVarCarryingInst DebugVarCarryingInst::getFromValue(SILValue value) {
69+
if (auto *svi = dyn_cast<SingleValueInstruction>(value)) {
70+
if (auto result = VarDeclCarryingInst(svi)) {
71+
switch (result.getKind()) {
72+
case VarDeclCarryingInst::Kind::Invalid:
73+
llvm_unreachable("ShouldKind have never seen this");
74+
case VarDeclCarryingInst::Kind::DebugValue:
75+
case VarDeclCarryingInst::Kind::AllocStack:
76+
case VarDeclCarryingInst::Kind::AllocBox:
77+
return DebugVarCarryingInst(svi);
78+
case VarDeclCarryingInst::Kind::GlobalAddr:
79+
case VarDeclCarryingInst::Kind::RefElementAddr:
80+
return DebugVarCarryingInst();
81+
}
82+
}
83+
}
84+
85+
if (auto *use = getSingleDebugUse(value))
86+
return DebugVarCarryingInst(use->getUser());
87+
88+
return DebugVarCarryingInst();
89+
}

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -382,22 +382,47 @@ static bool isReinitToInitConvertibleInst(SILInstruction *memInst) {
382382
}
383383
}
384384

385-
static void convertMemoryReinitToInitForm(SILInstruction *memInst) {
385+
static void insertDebugValueBefore(SILInstruction *insertPt,
386+
DebugVarCarryingInst debugVar,
387+
SILValue operand) {
388+
if (!debugVar) {
389+
return;
390+
}
391+
auto varInfo = debugVar.getVarInfo();
392+
if (!varInfo) {
393+
return;
394+
}
395+
SILBuilderWithScope debugInfoBuilder(insertPt);
396+
debugInfoBuilder.setCurrentDebugScope(debugVar->getDebugScope());
397+
debugInfoBuilder.createDebugValue(debugVar->getLoc(), operand,
398+
*varInfo, false, true);
399+
}
400+
401+
static void convertMemoryReinitToInitForm(SILInstruction *memInst,
402+
DebugVarCarryingInst debugVar) {
403+
SILValue dest;
386404
switch (memInst->getKind()) {
387405
default:
388406
llvm_unreachable("unsupported?!");
389407

390408
case SILInstructionKind::CopyAddrInst: {
391409
auto *cai = cast<CopyAddrInst>(memInst);
392410
cai->setIsInitializationOfDest(IsInitialization_t::IsInitialization);
393-
return;
411+
dest = cai->getDest();
412+
break;
394413
}
395414
case SILInstructionKind::StoreInst: {
396415
auto *si = cast<StoreInst>(memInst);
397416
si->setOwnershipQualifier(StoreOwnershipQualifier::Init);
398-
return;
417+
dest = si->getDest();
418+
break;
399419
}
400420
}
421+
422+
// Insert a new debug_value instruction after the reinitialization, so that
423+
// the debugger knows that the variable is in a usable form again.
424+
insertDebugValueBefore(memInst->getNextInstruction(), debugVar,
425+
stripAccessMarkers(dest));
401426
}
402427

403428
static bool memInstMustConsume(Operand *memOper) {
@@ -1151,7 +1176,8 @@ struct MoveOnlyAddressCheckerPImpl {
11511176
FieldSensitiveMultiDefPrunedLiveRange &liveness,
11521177
FieldSensitivePrunedLivenessBoundary &boundary);
11531178

1154-
void rewriteUses(FieldSensitiveMultiDefPrunedLiveRange &liveness,
1179+
void rewriteUses(MarkMustCheckInst *markedValue,
1180+
FieldSensitiveMultiDefPrunedLiveRange &liveness,
11551181
const FieldSensitivePrunedLivenessBoundary &boundary);
11561182

11571183
void handleSingleBlockDestroy(SILInstruction *destroy, bool isReinit);
@@ -2210,17 +2236,9 @@ void MoveOnlyAddressCheckerPImpl::insertDestroysOnBoundary(
22102236
if (!debugVar) {
22112237
return;
22122238
}
2213-
auto varInfo = debugVar.getVarInfo();
2214-
if (!varInfo) {
2215-
return;
2216-
}
2217-
SILBuilderWithScope debugInfoBuilder(insertPt);
2218-
debugInfoBuilder.setCurrentDebugScope(debugVar->getDebugScope());
2219-
debugInfoBuilder.createDebugValue(
2220-
debugVar->getLoc(),
2221-
SILUndef::get(debugVar.getOperandForDebugValueClone()->getType(),
2222-
insertPt->getModule()),
2223-
*varInfo, false, true);
2239+
insertDebugValueBefore(insertPt, debugVar,
2240+
SILUndef::get(debugVar.getOperandForDebugValueClone()->getType(),
2241+
insertPt->getModule()));
22242242
};
22252243

22262244
for (auto &pair : boundary.getLastUsers()) {
@@ -2326,6 +2344,7 @@ void MoveOnlyAddressCheckerPImpl::insertDestroysOnBoundary(
23262344
}
23272345

23282346
void MoveOnlyAddressCheckerPImpl::rewriteUses(
2347+
MarkMustCheckInst *markedValue,
23292348
FieldSensitiveMultiDefPrunedLiveRange &liveness,
23302349
const FieldSensitivePrunedLivenessBoundary &boundary) {
23312350
LLVM_DEBUG(llvm::dbgs() << "MoveOnlyAddressChecker Rewrite Uses!\n");
@@ -2336,12 +2355,15 @@ void MoveOnlyAddressCheckerPImpl::rewriteUses(
23362355
}
23372356
}
23382357

2358+
auto debugVar = DebugVarCarryingInst::getFromValue(
2359+
stripAccessMarkers(markedValue->getOperand()));
2360+
23392361
// Then convert all claimed reinits to inits.
23402362
for (auto reinitPair : addressUseState.reinitInsts) {
23412363
if (!isReinitToInitConvertibleInst(reinitPair.first))
23422364
continue;
23432365
if (!consumes.claimConsume(reinitPair.first, reinitPair.second))
2344-
convertMemoryReinitToInitForm(reinitPair.first);
2366+
convertMemoryReinitToInitForm(reinitPair.first, debugVar);
23452367
}
23462368

23472369
// Check all takes.
@@ -2524,7 +2546,7 @@ bool MoveOnlyAddressCheckerPImpl::performSingleCheck(
25242546
FieldSensitivePrunedLivenessBoundary boundary(liveness.getNumSubElements());
25252547
liveness.computeBoundary(boundary);
25262548
insertDestroysOnBoundary(markedAddress, liveness, boundary);
2527-
rewriteUses(liveness, boundary);
2549+
rewriteUses(markedAddress, liveness, boundary);
25282550

25292551
return true;
25302552
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %target-swift-frontend -emit-sil -g %s | %FileCheck %s
2+
// RUN: %target-swift-frontend -DADDRESS_ONLY -emit-sil -g %s | %FileCheck %s
3+
4+
struct Foo: ~Copyable {
5+
#if ADDRESS_ONLY
6+
private var x: Any
7+
#else
8+
private var x: Int
9+
#endif
10+
}
11+
12+
@_silgen_name("use")
13+
func use(_: inout Foo)
14+
15+
// CHECK-LABEL: sil {{.*}} @${{.*}}3bar
16+
func bar(_ x: consuming Foo, y: consuming Foo, z: consuming Foo) {
17+
// CHECK: [[X:%.*]] = alloc_stack{{.*}} $Foo, var, name "x"
18+
19+
// CHECK: [[USE:%.*]] = function_ref @use
20+
// CHECK: apply [[USE]]
21+
// CHECK: debug_value undef : $*Foo, var, name "x"
22+
use(&x)
23+
let _ = x
24+
25+
// CHECK: debug_value undef : $*Foo, var, name "y"
26+
// CHECK: debug_value [[X]] : $*Foo, var, name "x"
27+
x = y
28+
// CHECK: [[USE:%.*]] = function_ref @use
29+
// CHECK: apply [[USE]]
30+
// CHECK: debug_value undef : $*Foo, var, name "x"
31+
use(&x)
32+
let _ = x
33+
34+
// CHECK: debug_value undef : $*Foo, var, name "z"
35+
// CHECK: debug_value [[X]] : $*Foo, var, name "x"
36+
x = z
37+
// CHECK: [[USE:%.*]] = function_ref @use
38+
// CHECK: apply [[USE]]
39+
// CHECK: debug_value undef : $*Foo, var, name "x"
40+
use(&x)
41+
}

0 commit comments

Comments
 (0)