Skip to content

Commit f6deefd

Browse files
committed
[DebugInfo] [Mem2Reg] Move debug info promotion to salvageDebugInfo
1 parent 3d94715 commit f6deefd

File tree

8 files changed

+59
-97
lines changed

8 files changed

+59
-97
lines changed

lib/SILOptimizer/Transforms/SILMem2Reg.cpp

Lines changed: 4 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -318,51 +318,6 @@ static bool isDebugValueOfAllocStack(DebugValueInst *dvi, AllocStackInst *asi) {
318318
return sbi->getDest() == asi;
319319
}
320320

321-
/// Promote a DebugValue w/ address value to a DebugValue of non-address value.
322-
static void promoteDebugValueAddr(DebugValueInst *dvai, SILValue value,
323-
SILBuilderContext &ctx,
324-
InstructionDeleter &deleter) {
325-
assert(dvai->getOperand()->getType().isLoadable(*dvai->getFunction()) &&
326-
"Unexpected promotion of address-only type!");
327-
assert(value && "Expected valid value");
328-
329-
// Avoid inserting the same debug_value twice.
330-
//
331-
// We remove the di expression when comparing since:
332-
//
333-
// 1. dvai is on will always have the deref diexpr since it is on addresses.
334-
//
335-
// 2. We are only trying to delete debug_var that are on values... values will
336-
// never have an op_deref meaning that the comparison will always fail and
337-
// not serve out purpose here.
338-
auto dvaiWithoutDIExpr = dvai->getVarInfo()->withoutDIExpr();
339-
for (auto *use : value->getUses()) {
340-
if (auto *dvi = dyn_cast<DebugValueInst>(use->getUser())) {
341-
if (!dvi->hasAddrVal() && *dvi->getVarInfo() == dvaiWithoutDIExpr) {
342-
deleter.forceDelete(dvai);
343-
return;
344-
}
345-
}
346-
}
347-
348-
// Drop op_deref if dvai is actually a debug_value instruction
349-
auto varInfo = *dvai->getVarInfo();
350-
if (isa<DebugValueInst>(dvai)) {
351-
auto &diExpr = varInfo.DIExpr;
352-
// FIXME: There should always be a DIExpr starting with an op_deref here
353-
// The debug_value is attached to a pointer type, and those don't exist
354-
// in Swift, so they should always be dereferenced.
355-
// However, this rule is broken in a lot of spaces, so we have to leave
356-
// this check to recover from wrong info
357-
if (diExpr && diExpr.startsWithDeref())
358-
diExpr.eraseElement(diExpr.element_begin());
359-
}
360-
361-
SILBuilderWithScope b(dvai, ctx);
362-
b.createDebugValue(dvai->getLoc(), value, std::move(varInfo));
363-
deleter.forceDelete(dvai);
364-
}
365-
366321
/// Returns true if \p I is a load which loads from \p ASI.
367322
static bool isLoadFromStack(SILInstruction *i, AllocStackInst *asi) {
368323
if (!isa<LoadInst>(i) && !isa<LoadBorrowInst>(i))
@@ -1172,14 +1127,8 @@ SILInstruction *StackAllocationPromoter::promoteAllocationInBlock(
11721127
continue;
11731128
}
11741129

1175-
// Replace debug_value w/ address value with debug_value of
1176-
// the promoted value.
1177-
// if we have a valid value to use at this point. Otherwise we'll
1178-
// promote this when we deal with hooking up phis.
1130+
// Debug values will automatically be salvaged, we can ignore them
11791131
if (auto *dvi = DebugValueInst::hasAddrVal(inst)) {
1180-
if (isDebugValueOfAllocStack(dvi, asi) && runningVals)
1181-
promoteDebugValueAddr(dvi, runningVals->value.replacement(asi, dvi),
1182-
ctx, deleter);
11831132
continue;
11841133
}
11851134

@@ -1432,12 +1381,8 @@ void StackAllocationPromoter::fixBranchesAndUses(
14321381
// on.
14331382
SILBasicBlock *userBlock = user->getParent();
14341383

1384+
// Debug values will automatically be salvaged, we can ignore them
14351385
if (auto *dvi = DebugValueInst::hasAddrVal(user)) {
1436-
// Replace debug_value w/ address-type value with
1437-
// a new debug_value w/ promoted value.
1438-
auto def = getEffectiveLiveInValues(phiBlocks, userBlock);
1439-
promoteDebugValueAddr(dvi, def.replacement(asi, dvi), ctx, deleter);
1440-
++NumInstRemoved;
14411386
continue;
14421387
}
14431388

@@ -2036,14 +1981,10 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *asi) {
20361981
continue;
20371982
}
20381983

2039-
// Replace debug_value w/ address value with debug_value of
2040-
// the promoted value.
1984+
// Debug values will automatically be salvaged, we can ignore them
20411985
if (auto *dvi = DebugValueInst::hasAddrVal(inst)) {
20421986
if (isDebugValueOfAllocStack(dvi, asi)) {
2043-
if (runningVals) {
2044-
promoteDebugValueAddr(dvi, runningVals->value.replacement(asi, dvi),
2045-
ctx, deleter);
2046-
} else {
1987+
if (!runningVals) {
20471988
// Drop debug_value of uninitialized void values.
20481989
assert(asi->getElementType().isVoid() &&
20491990
"Expected initialization of non-void type!");

lib/SILOptimizer/Utils/GenericCloner.cpp

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ void GenericCloner::populateCloned() {
6868
SILBasicBlock *ClonedEntryBB = Cloned->createBasicBlock();
6969
getBuilder().setInsertionPoint(ClonedEntryBB);
7070

71+
RemappedScopeCache.insert({Original.getDebugScope(), Cloned->getDebugScope()});
72+
7173
// Create the entry basic block with the function arguments.
7274
auto origConv = Original.getConventions();
7375
unsigned ArgIdx = 0;
@@ -138,26 +140,6 @@ void GenericCloner::populateCloned() {
138140
mappedType, OrigArg->getDecl());
139141
NewArg->copyFlags(cast<SILFunctionArgument>(OrigArg));
140142

141-
// Try to create a new debug_value from an existing debug_value w/
142-
// address value for the argument. We do this before storing to
143-
// ensure that when we are cloning code in ossa the argument has
144-
// not been consumed by the store below.
145-
for (Operand *ArgUse : OrigArg->getUses()) {
146-
if (auto *DVI = DebugValueInst::hasAddrVal(ArgUse->getUser())) {
147-
auto *oldScope = getBuilder().getCurrentDebugScope();
148-
getBuilder().setCurrentDebugScope(
149-
remapScope(DVI->getDebugScope()));
150-
auto VarInfo = DVI->getVarInfo();
151-
assert(VarInfo && VarInfo->DIExpr &&
152-
"No DebugVarInfo or no DIExpr operand?");
153-
// Drop the op_deref
154-
VarInfo->DIExpr.eraseElement(VarInfo->DIExpr.element_begin());
155-
getBuilder().createDebugValue(DVI->getLoc(), NewArg, *VarInfo);
156-
getBuilder().setCurrentDebugScope(oldScope);
157-
break;
158-
}
159-
}
160-
161143
// Store the new direct parameter to an alloc_stack.
162144
createAllocStack();
163145
SILValue addr;

lib/SILOptimizer/Utils/InstOptUtils.cpp

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1818,6 +1818,23 @@ void swift::endLifetimeAtLeakingBlocks(SILValue value,
18181818
});
18191819
}
18201820

1821+
// Replace a store with an appropriate debug value
1822+
// T is StoreInst or StoreBorrowInst
1823+
template <typename T>
1824+
static void transferStoreDebugValue(DebugVarCarryingInst DefiningInst, T *SI) {
1825+
auto VarInfo = DefiningInst.getVarInfo();
1826+
if (!VarInfo)
1827+
return;
1828+
if (!VarInfo->Loc && !SI->getLoc().hasSameSourceLocation(DefiningInst->getLoc()))
1829+
VarInfo->Loc = DefiningInst->getLoc();
1830+
if (!VarInfo->Scope && SI->getDebugScope() != DefiningInst->getDebugScope())
1831+
VarInfo->Scope = DefiningInst->getDebugScope();
1832+
if (VarInfo->DIExpr.startsWithDeref())
1833+
VarInfo->DIExpr.eraseElement(VarInfo->DIExpr.element_begin());
1834+
SILBuilder(SI, DefiningInst->getDebugScope())
1835+
.createDebugValue(SI->getLoc(), SI->getSrc(), *VarInfo);
1836+
}
1837+
18211838
// TODO: this currently fails to notify the pass with notifyNewInstruction.
18221839
//
18231840
// TODO: whenever a debug_value is inserted at a new location, check that no
@@ -1831,15 +1848,20 @@ void swift::salvageDebugInfo(SILInstruction *I) {
18311848
if (SILValue DestVal = SI->getDest())
18321849
if (auto *ASI = dyn_cast_or_null<AllocStackInst>(
18331850
DestVal.getDefiningInstruction())) {
1834-
if (auto VarInfo = ASI->getVarInfo()) {
1835-
// Always propagate destination location for incoming arguments (as
1836-
// their location must be unique) as well as when store source
1837-
// location is compiler-generated.
1838-
bool UseDestLoc = VarInfo->ArgNo || SI->getLoc().isAutoGenerated();
1839-
SILBuilder(SI, ASI->getDebugScope())
1840-
.createDebugValue(UseDestLoc ? ASI->getLoc() : SI->getLoc(),
1841-
SI->getSrc(), *VarInfo);
1842-
}
1851+
transferStoreDebugValue(ASI, SI);
1852+
for (Operand *U : getDebugUses(ASI))
1853+
transferStoreDebugValue(U->getUser(), SI);
1854+
}
1855+
}
1856+
if (auto *SI = dyn_cast<StoreBorrowInst>(I)) {
1857+
if (SILValue DestVal = SI->getDest())
1858+
if (auto *ASI = dyn_cast_or_null<AllocStackInst>(
1859+
DestVal.getDefiningInstruction())) {
1860+
transferStoreDebugValue(ASI, SI);
1861+
for (Operand *U : getDebugUses(ASI))
1862+
transferStoreDebugValue(U->getUser(), SI);
1863+
for (Operand *U : getDebugUses(SI))
1864+
transferStoreDebugValue(U->getUser(), SI);
18431865
}
18441866
}
18451867
// If a `struct` SIL instruction is "unwrapped" and removed,

lib/SILOptimizer/Utils/InstructionDeleter.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ void InstructionDeleter::deleteWithUses(SILInstruction *inst, bool fixLifetimes,
228228
// Recursively visit all uses while growing toDeleteInsts in def-use order and
229229
// dropping dead operands.
230230
SmallVector<SILInstruction *, 4> toDeleteInsts;
231+
SmallVector<Operand *, 4> toDropUses;
231232

232233
toDeleteInsts.push_back(inst);
233234
swift::salvageDebugInfo(inst);
@@ -242,11 +243,15 @@ void InstructionDeleter::deleteWithUses(SILInstruction *inst, bool fixLifetimes,
242243
assert(!isa<BranchInst>(user) && "can't delete phis");
243244

244245
toDeleteInsts.push_back(user);
246+
toDropUses.push_back(use);
245247
swift::salvageDebugInfo(user);
246-
use->drop();
247248
}
248249
}
249250
}
251+
// Drop all after salvage debug info has been run
252+
for (auto *use : toDropUses) {
253+
use->drop();
254+
}
250255
// Process the remaining operands. Insert destroys for consuming
251256
// operands. Track newly dead operand values. Instructions with multiple dead
252257
// operands may occur in toDeleteInsts multiple times.

test/AutoDiff/compiler_crashers_fixed/58660-conflicting-debug-info-inlining.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ struct MyModel: Differentiable {
4747
// CHECK-LABEL: // pullback of MyModel.member4()
4848
// CHECK-NOT: debug_value %{{.*}} : $MyModel.TangentVector, var, name %{{.*}}, argno 1, scope
4949
// CHECK: bb0(%{{.*}} : $_AD__$s4main7MyModelV7member4yyF_bb3__Pred__src_0_wrt_0):
50-
// CHECK: debug_value %{{.*}} : $MyModel.TangentVector, var, name "derivative of 'self' in scope at {{.*}} (scope #1)", scope
50+
// CHECK: debug_value %{{.*}} : $MyModel.TangentVector, var, (name "derivative of 'self' in scope at {{.*}} (scope #1)"{{.*}}), scope
5151
// Must be a differentiable type.
5252
var localVar: Float = 0
5353

test/DebugInfo/sroa_debug_value.sil

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %target-sil-opt -enable-sil-verify-all -sil-print-debuginfo -sroa %s | %FileCheck --check-prefix=CHECK-SROA %s
2+
// RUN: %target-sil-opt -enable-sil-verify-all -sil-print-debuginfo -sroa -mem2reg %s | %FileCheck --check-prefix=CHECK-MEM2REG %s
23
sil_stage canonical
34

45
import Builtin
@@ -51,5 +52,14 @@ bb0(%0 : $Int64, %1 : $Int64):
5152
store %1 to %15 : $*Int64, loc "sroa.swift":10:17, scope 2
5253
// CHECK-SROA: store %1 to %[[ALLOC_Y]]
5354
dealloc_stack %4 : $*MyStruct, loc "sroa.swift":8:9, scope 2
55+
// Make sure function arguments' SSA values are properly connected to both source variables
56+
// CHECK-MEM2REG: debug_value %0 : $Int64, var, (name "my_struct", loc "sroa.swift":8:9
57+
// CHECK-MEM2REG-SAME: type $*MyStruct, expr op_fragment:#MyStruct.x
58+
// CHECK-MEM2REG: debug_value %0 : $Int64, let, (name "my_copy", loc "sroa.swift":7:10
59+
// CHECK-MEM2REG-SAME: type $MyStruct, expr op_fragment:#MyStruct.x
60+
// CHECK-MEM2REG: debug_value %1 : $Int64, var, (name "my_struct", loc "sroa.swift":8:9
61+
// CHECK-MEM2REG-SAME: type $*MyStruct, expr op_fragment:#MyStruct.y
62+
// CHECK-MEM2REG: debug_value %1 : $Int64, let, (name "my_copy", loc "sroa.swift":7:10
63+
// CHECK-MEM2REG-SAME: type $MyStruct, expr op_fragment:#MyStruct.y
5464
return %0 : $Int64, loc "sroa.swift":11:5, scope 2
5565
} // end sil function 'foo'

test/SILOptimizer/mem2reg_lifetime_nontrivial.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,8 +595,8 @@ bb3:
595595
// CHECK-NOT: alloc_stack
596596
// CHECK-NOT: debug_value {{.*}} expr op_deref
597597
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $Klass):
598+
// CHECK: debug_value [[INSTANCE]]
598599
// CHECK: [[LIFETIME_OWNED:%[^,]+]] = move_value [lexical] [[INSTANCE]]
599-
// CHECK: debug_value [[LIFETIME_OWNED]]
600600
// CHECK-LABEL: } // end sil function 'mem2reg_debug_value'
601601
sil [ossa] @mem2reg_debug_value : $@convention(thin) (@owned Klass) -> @owned Klass {
602602
bb0(%0 : @owned $Klass):

test/SILOptimizer/mem2reg_resilient_lifetime.sil

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,19 @@ public struct ResilientStruct {
1111
// CHECK-LABEL: sil [ossa] @mem2reg_debug_value :
1212
// CHECK: {{bb[^,]+}}([[REGISTER_0:%[^,]+]] : $*ResilientStruct):
1313
// CHECK-NEXT: [[REGISTER_1:%[^,]+]] = load [copy] [[REGISTER_0]]
14+
// CHECK-NEXT: debug_value [[REGISTER_1]] : $ResilientStruct, var, name "before"
1415
// CHECK-NEXT: [[REGISTER_3:%[^,]+]] = move_value [lexical] [[REGISTER_1]]
15-
// CHECK-NEXT: debug_value [[REGISTER_3]]
16+
// CHECK-NEXT: debug_value [[REGISTER_3]] : $ResilientStruct, let, name "after"
1617
// CHECK-NEXT: destroy_value [[REGISTER_3]]
1718
// CHECK-LABEL: } // end sil function 'mem2reg_debug_value'
1819
sil [ossa] @mem2reg_debug_value : $@convention(thin) (@in_guaranteed ResilientStruct) -> () {
1920
bb0(%0 : $*ResilientStruct):
2021
%1 = alloc_stack [lexical] $ResilientStruct
2122
%2 = load [copy] %0 : $*ResilientStruct
2223
store %2 to [init] %1 : $*ResilientStruct
23-
debug_value %1 : $*ResilientStruct, expr op_deref
24+
debug_value %1 : $*ResilientStruct, var, name "before", expr op_deref
2425
%3 = load [take] %1 : $*ResilientStruct
26+
debug_value %3 : $ResilientStruct, let, name "after"
2527
destroy_value %3 : $ResilientStruct
2628
dealloc_stack %1 : $*ResilientStruct
2729
%4 = tuple ()

0 commit comments

Comments
 (0)