Skip to content

Commit a31d15c

Browse files
authored
Merge pull request #72964 from Snowy1803/mem2reg-salvage-store
[DebugInfo] Salvage all stores
2 parents 2f954ef + 584d1db commit a31d15c

File tree

16 files changed

+202
-134
lines changed

16 files changed

+202
-134
lines changed

include/swift/SIL/SILBuilder.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,11 @@ class SILBuilder {
262262
/// scopes. To avoid a verification error later in the pipeline, drop all
263263
/// variables without a proper source location.
264264
bool shouldDropVariable(SILDebugVariable Var, SILLocation Loc) {
265-
return !Var.ArgNo && Loc.isSynthesizedAST();
265+
if (Var.ArgNo)
266+
return false;
267+
if (Var.Loc)
268+
return Var.Loc->isSynthesizedAST();
269+
return Loc.isSynthesizedAST();
266270
}
267271

268272

include/swift/SIL/SILLocation.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,16 @@ class SILLocation {
391391
/// Check is this location is part of a function's implicit prologue.
392392
bool isInPrologue() const { return kindAndFlags.fields.inPrologue; }
393393

394+
/// Returns this location with the auto-generated and prologue bits stripped.
395+
/// These bits only make sense for instructions, and should be stripped for
396+
/// variables.
397+
SILLocation strippedForDebugVariable() const {
398+
SILLocation loc = *this;
399+
loc.kindAndFlags.fields.autoGenerated = false;
400+
loc.kindAndFlags.fields.inPrologue = false;
401+
return loc;
402+
}
403+
394404
/// Check if the corresponding source code location definitely points
395405
/// to the end of the AST node.
396406
bool pointsToEnd() const;

include/swift/SILOptimizer/Utils/DebugOptUtils.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ inline void deleteAllDebugUses(SILInstruction *inst,
4848
/// new `debug_value` instruction before \p I is deleted.
4949
void salvageDebugInfo(SILInstruction *I);
5050

51+
/// Transfer debug info associated with the store-like instruction \p SI to a
52+
/// new `debug_value` instruction before \p SI is deleted.
53+
/// \param SI The store instruction being deleted
54+
/// \param SrcVal The old source, where the debuginfo should be propagated to
55+
/// \param DestVal The old destination, where the debuginfo was
56+
void salvageStoreDebugInfo(SILInstruction *SI,
57+
SILValue SrcVal, SILValue DestVal);
58+
5159
/// Transfer debug information associated with the result of \p load to the
5260
/// load's address operand.
5361
///

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3186,10 +3186,14 @@ void IRGenDebugInfoImpl::emitVariableDeclaration(
31863186
// Create the descriptor for the variable.
31873187
unsigned DVarLine = DInstLine;
31883188
uint16_t DVarCol = DInstLoc.Column;
3189-
if (VarInfo.Loc) {
3190-
auto DVarLoc = getStartLocation(VarInfo.Loc);
3191-
DVarLine = DVarLoc.Line;
3192-
DVarCol = DVarLoc.Column;
3189+
auto VarInfoLoc = VarInfo.Loc ? VarInfo.Loc : DbgInstLoc;
3190+
if (VarInfoLoc) {
3191+
auto VarLoc = VarInfoLoc->strippedForDebugVariable();
3192+
if (VarLoc != DbgInstLoc) {
3193+
auto DVarLoc = getStartLocation(VarLoc);
3194+
DVarLine = DVarLoc.Line;
3195+
DVarCol = DVarLoc.Column;
3196+
}
31933197
}
31943198
llvm::DIScope *VarScope = Scope;
31953199
if (ArgNo == 0 && VarInfo.Scope) {

lib/SIL/Verifier/MemoryLifetimeVerifier.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -756,8 +756,7 @@ void MemoryLifetimeVerifier::checkBlock(SILBasicBlock *block, Bits &bits) {
756756
// an alloc_stack), which don't have any `op_deref` in its
757757
// di-expression, because that memory doesn't need to be initialized
758758
// when `debug_value` is referencing it.
759-
if (cast<DebugValueInst>(&I)->hasAddrVal() &&
760-
cast<DebugValueInst>(&I)->exprStartsWithDeref())
759+
if (!DebugValueInst::hasAddrVal(&I))
761760
requireBitsSet(bits, I.getOperand(0), &I);
762761
break;
763762
case SILInstructionKind::UncheckedTakeEnumDataAddrInst: {

lib/SILOptimizer/Transforms/CopyForwarding.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
#include "swift/SILOptimizer/PassManager/Passes.h"
7070
#include "swift/SILOptimizer/PassManager/Transforms.h"
7171
#include "swift/SILOptimizer/Utils/CFGOptUtils.h"
72+
#include "swift/SILOptimizer/Utils/DebugOptUtils.h"
7273
#include "swift/SILOptimizer/Utils/ValueLifetime.h"
7374
#include "llvm/ADT/SetVector.h"
7475
#include "llvm/ADT/Statistic.h"
@@ -698,6 +699,8 @@ propagateCopy(CopyAddrInst *CopyInst) {
698699
SILBuilderWithScope(CurrentCopy)
699700
.createDestroyAddr(CurrentCopy->getLoc(), CurrentCopy->getDest());
700701
}
702+
swift::salvageStoreDebugInfo(CurrentCopy, CurrentCopy->getSrc(),
703+
CurrentCopy->getDest());
701704
CurrentCopy->eraseFromParent();
702705
HasChanged = true;
703706
++NumCopyForward;
@@ -706,6 +709,8 @@ propagateCopy(CopyAddrInst *CopyInst) {
706709
// Forward propagation failed. Attempt to backward propagate.
707710
if (CurrentCopy->isInitializationOfDest() && backwardPropagateCopy()) {
708711
LLVM_DEBUG(llvm::dbgs() << " Reversing Copy:" << *CurrentCopy);
712+
swift::salvageStoreDebugInfo(CurrentCopy, CurrentCopy->getDest(),
713+
CurrentCopy->getSrc());
709714
CurrentCopy->eraseFromParent();
710715
HasChanged = true;
711716
++NumCopyBackward;
@@ -817,6 +822,9 @@ forwardDeadTempCopy(CopyAddrInst *destCopy) {
817822
.createDestroyAddr(srcCopy->getLoc(), srcCopy->getDest());
818823
}
819824

825+
// Salvage debug values before deleting them.
826+
swift::salvageStoreDebugInfo(srcCopy, srcCopy->getSrc(), srcCopy->getDest());
827+
820828
// Delete all dead debug_value instructions
821829
for (auto *deadDebugUser : debugInstsToDelete) {
822830
deadDebugUser->eraseFromParent();
@@ -1190,9 +1198,13 @@ bool CopyForwarding::backwardPropagateCopy() {
11901198
// Now that an init was found, it is safe to substitute all recorded uses
11911199
// with the copy's dest.
11921200
for (auto *Oper : ValueUses) {
1193-
Oper->set(CurrentCopy->getDest());
1194-
if (isa<CopyAddrInst>(Oper->getUser()))
1201+
if (auto *SI = dyn_cast<CopyAddrInst>(Oper->getUser())) {
11951202
HasForwardedToCopy = true;
1203+
// This instruction gets "replaced", so we need to salvage its previous
1204+
// debug info.
1205+
swift::salvageStoreDebugInfo(SI, SI->getSrc(), SI->getDest());
1206+
}
1207+
Oper->set(CurrentCopy->getDest());
11961208
}
11971209
return true;
11981210
}

lib/SILOptimizer/Transforms/SILMem2Reg.cpp

Lines changed: 3 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -301,68 +301,6 @@ replaceDestroy(DestroyAddrInst *dai, SILValue newValue, SILBuilderContext &ctx,
301301
prepareForDeletion(dai, instructionsToDelete);
302302
}
303303

304-
/// Whether the specified debug_value's operand names the address at the
305-
/// indicated alloc_stack.
306-
///
307-
/// If it's a guaranteed alloc_stack (i.e. a store_borrow location), that
308-
/// includes the values produced by any store_borrows whose destinations are the
309-
/// alloc_stack since those values amount to aliases for the alloc_stack's
310-
/// storage.
311-
static bool isDebugValueOfAllocStack(DebugValueInst *dvi, AllocStackInst *asi) {
312-
auto value = dvi->getOperand();
313-
if (value == asi)
314-
return true;
315-
auto *sbi = dyn_cast<StoreBorrowInst>(value);
316-
if (!sbi)
317-
return false;
318-
return sbi->getDest() == asi;
319-
}
320-
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-
366304
/// Returns true if \p I is a load which loads from \p ASI.
367305
static bool isLoadFromStack(SILInstruction *i, AllocStackInst *asi) {
368306
if (!isa<LoadInst>(i) && !isa<LoadBorrowInst>(i))
@@ -1172,14 +1110,8 @@ SILInstruction *StackAllocationPromoter::promoteAllocationInBlock(
11721110
continue;
11731111
}
11741112

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.
1113+
// Debug values will automatically be salvaged, we can ignore them.
11791114
if (auto *dvi = DebugValueInst::hasAddrVal(inst)) {
1180-
if (isDebugValueOfAllocStack(dvi, asi) && runningVals)
1181-
promoteDebugValueAddr(dvi, runningVals->value.replacement(asi, dvi),
1182-
ctx, deleter);
11831115
continue;
11841116
}
11851117

@@ -1432,12 +1364,8 @@ void StackAllocationPromoter::fixBranchesAndUses(
14321364
// on.
14331365
SILBasicBlock *userBlock = user->getParent();
14341366

1367+
// Debug values will automatically be salvaged, we can ignore them.
14351368
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;
14411369
continue;
14421370
}
14431371

@@ -2036,20 +1964,8 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *asi) {
20361964
continue;
20371965
}
20381966

2039-
// Replace debug_value w/ address value with debug_value of
2040-
// the promoted value.
1967+
// Debug values will automatically be salvaged, we can ignore them.
20411968
if (auto *dvi = DebugValueInst::hasAddrVal(inst)) {
2042-
if (isDebugValueOfAllocStack(dvi, asi)) {
2043-
if (runningVals) {
2044-
promoteDebugValueAddr(dvi, runningVals->value.replacement(asi, dvi),
2045-
ctx, deleter);
2046-
} else {
2047-
// Drop debug_value of uninitialized void values.
2048-
assert(asi->getElementType().isVoid() &&
2049-
"Expected initialization of non-void type!");
2050-
deleter.forceDelete(dvi);
2051-
}
2052-
}
20531969
continue;
20541970
}
20551971

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: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1826,6 +1826,44 @@ void swift::endLifetimeAtLeakingBlocks(SILValue value,
18261826
});
18271827
}
18281828

1829+
/// Create a new debug value from a store and a debug variable.
1830+
static void transferStoreDebugValue(DebugVarCarryingInst DefiningInst,
1831+
SILInstruction *SI,
1832+
SILValue original) {
1833+
auto VarInfo = DefiningInst.getVarInfo();
1834+
if (!VarInfo)
1835+
return;
1836+
// Transfer the location and scope of the debug value to the debug variable,
1837+
// unless they are the same, in which case we don't need to store it twice.
1838+
// That way, the variable will point to its declaration, and the debug_value
1839+
// will point to the assignment point.
1840+
if (!VarInfo->Loc && !SI->getLoc().hasSameSourceLocation(DefiningInst->getLoc()))
1841+
VarInfo->Loc = DefiningInst->getLoc();
1842+
if (!VarInfo->Scope && SI->getDebugScope() != DefiningInst->getDebugScope())
1843+
VarInfo->Scope = DefiningInst->getDebugScope();
1844+
// Fix the op_deref.
1845+
if (!isa<CopyAddrInst>(SI) && VarInfo->DIExpr.startsWithDeref())
1846+
VarInfo->DIExpr.eraseElement(VarInfo->DIExpr.element_begin());
1847+
else if (isa<CopyAddrInst>(SI) && !VarInfo->DIExpr.startsWithDeref())
1848+
VarInfo->DIExpr.prependElements({
1849+
SILDIExprElement::createOperator(SILDIExprOperator::Dereference)});
1850+
// Note: The instruction should logically be in the SI's scope.
1851+
// However, LLVM does not support variables and stores in different scopes,
1852+
// so we use the variable's scope.
1853+
SILBuilder(SI, DefiningInst->getDebugScope())
1854+
.createDebugValue(SI->getLoc(), original, *VarInfo);
1855+
}
1856+
1857+
void swift::salvageStoreDebugInfo(SILInstruction *SI,
1858+
SILValue SrcVal, SILValue DestVal) {
1859+
if (auto *ASI = dyn_cast_or_null<AllocStackInst>(
1860+
DestVal.getDefiningInstruction())) {
1861+
transferStoreDebugValue(ASI, SI, SrcVal);
1862+
for (Operand *U : getDebugUses(ASI))
1863+
transferStoreDebugValue(U->getUser(), SI, SrcVal);
1864+
}
1865+
}
1866+
18291867
// TODO: this currently fails to notify the pass with notifyNewInstruction.
18301868
//
18311869
// TODO: whenever a debug_value is inserted at a new location, check that no
@@ -1837,18 +1875,13 @@ void swift::salvageDebugInfo(SILInstruction *I) {
18371875

18381876
if (auto *SI = dyn_cast<StoreInst>(I)) {
18391877
if (SILValue DestVal = SI->getDest())
1840-
if (auto *ASI = dyn_cast_or_null<AllocStackInst>(
1841-
DestVal.getDefiningInstruction())) {
1842-
if (auto VarInfo = ASI->getVarInfo()) {
1843-
// Always propagate destination location for incoming arguments (as
1844-
// their location must be unique) as well as when store source
1845-
// location is compiler-generated.
1846-
bool UseDestLoc = VarInfo->ArgNo || SI->getLoc().isAutoGenerated();
1847-
SILBuilder(SI, ASI->getDebugScope())
1848-
.createDebugValue(UseDestLoc ? ASI->getLoc() : SI->getLoc(),
1849-
SI->getSrc(), *VarInfo);
1850-
}
1851-
}
1878+
salvageStoreDebugInfo(SI, SI->getSrc(), DestVal);
1879+
}
1880+
if (auto *SI = dyn_cast<StoreBorrowInst>(I)) {
1881+
if (SILValue DestVal = SI->getDest())
1882+
salvageStoreDebugInfo(SI, SI->getSrc(), DestVal);
1883+
for (Operand *U : getDebugUses(SI))
1884+
transferStoreDebugValue(U->getUser(), SI, SI->getSrc());
18521885
}
18531886
// If a `struct` SIL instruction is "unwrapped" and removed,
18541887
// for instance, in favor of using its enclosed value directly,

lib/SILOptimizer/Utils/InstructionDeleter.cpp

Lines changed: 5 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,14 @@ 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();
250254
// Process the remaining operands. Insert destroys for consuming
251255
// operands. Track newly dead operand values. Instructions with multiple dead
252256
// 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

0 commit comments

Comments
 (0)