Skip to content

Commit 5b17a5e

Browse files
Merge pull request #73528 from Snowy1803/6.0-rdar127348128
[6.0] [DebugInfo] Salvage stores + Fix verifier crash for complex switch
2 parents 43c8c2e + e1863c9 commit 5b17a5e

24 files changed

+312
-181
lines changed

include/swift/SIL/SILBuilder.h

Lines changed: 8 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

@@ -419,6 +423,9 @@ class SILBuilder {
419423
#else
420424
(void)skipVarDeclAssert;
421425
#endif
426+
// Don't apply location overrides on variables.
427+
if (Var && !Var->Loc)
428+
Var->Loc = Loc;
422429
return insert(AllocStackInst::create(
423430
getSILDebugLocation(Loc, true), elementType, getFunction(),
424431
substituteAnonymousArgs(Name, Var, Loc), dynamic, isLexical,

include/swift/SIL/SILInstruction.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2083,6 +2083,13 @@ class AllocStackInst final
20832083
/// VarDecl.
20842084
void setIsFromVarDecl() { sharedUInt8().AllocStackInst.fromVarDecl = true; }
20852085

2086+
/// Return the SILLocation for the debug variable.
2087+
SILLocation getVarLoc() const {
2088+
if (hasAuxDebugLocation())
2089+
return *getTrailingObjects<SILLocation>();
2090+
return getLoc();
2091+
}
2092+
20862093
/// Return the debug variable information attached to this instruction.
20872094
std::optional<SILDebugVariable> getVarInfo() const {
20882095
// If we used to have debug info attached but our debug info is now
@@ -5340,6 +5347,13 @@ class DebugValueInst final
53405347
/// or null if we don't have one.
53415348
VarDecl *getDecl() const;
53425349

5350+
/// Return the SILLocation for the debug variable.
5351+
SILLocation getVarLoc() const {
5352+
if (hasAuxDebugLocation())
5353+
return *getTrailingObjects<SILLocation>();
5354+
return getLoc();
5355+
}
5356+
53435357
/// Return the debug variable information attached to this instruction.
53445358
std::optional<SILDebugVariable> getVarInfo() const {
53455359
std::optional<SILType> AuxVarType;

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/IR/SILInstructions.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,15 @@ AllocStackInst *AllocStackInst::create(SILDebugLocation Loc,
266266
IsLexical_t isLexical,
267267
IsFromVarDecl_t isFromVarDecl,
268268
UsesMoveableValueDebugInfo_t wasMoved) {
269+
// Don't store the same information twice.
270+
if (Var) {
271+
if (Var->Loc == Loc.getLocation())
272+
Var->Loc = {};
273+
if (Var->Scope == Loc.getScope())
274+
Var->Scope = nullptr;
275+
if (Var->Type == elementType)
276+
Var->Type = {};
277+
}
269278
SmallVector<SILValue, 8> TypeDependentOperands;
270279
collectTypeDependentOperands(TypeDependentOperands, F,
271280
elementType.getASTType());
@@ -277,6 +286,9 @@ AllocStackInst *AllocStackInst::create(SILDebugLocation Loc,
277286
}
278287

279288
VarDecl *AllocationInst::getDecl() const {
289+
if (auto ASI = dyn_cast<AllocStackInst>(this)) {
290+
return ASI->getVarLoc().getAsASTNode<VarDecl>();
291+
}
280292
return getLoc().getAsASTNode<VarDecl>();
281293
}
282294

@@ -460,6 +472,13 @@ DebugValueInst *DebugValueInst::create(SILDebugLocation DebugLoc,
460472
SILDebugVariable Var, bool poisonRefs,
461473
UsesMoveableValueDebugInfo_t wasMoved,
462474
bool trace) {
475+
// Don't store the same information twice.
476+
if (Var.Loc == DebugLoc.getLocation())
477+
Var.Loc = {};
478+
if (Var.Scope == DebugLoc.getScope())
479+
Var.Scope = nullptr;
480+
if (Var.Type == Operand->getType().getObjectType())
481+
Var.Type = {};
463482
void *buf = allocateDebugVarCarryingInst<DebugValueInst>(M, Var);
464483
return ::new (buf)
465484
DebugValueInst(DebugLoc, Operand, Var, poisonRefs, wasMoved, trace);
@@ -474,9 +493,8 @@ DebugValueInst::createAddr(SILDebugLocation DebugLoc, SILValue Operand,
474493
if (!isa<AllocStackInst>(Operand))
475494
Var.DIExpr.prependElements(
476495
{SILDIExprElement::createOperator(SILDIExprOperator::Dereference)});
477-
void *buf = allocateDebugVarCarryingInst<DebugValueInst>(M, Var);
478-
return ::new (buf) DebugValueInst(DebugLoc, Operand, Var,
479-
/*poisonRefs=*/false, wasMoved, trace);
496+
return DebugValueInst::create(DebugLoc, Operand, M, Var,
497+
/*poisonRefs=*/false, wasMoved, trace);
480498
}
481499

482500
bool DebugValueInst::exprStartsWithDeref() const {
@@ -490,7 +508,7 @@ bool DebugValueInst::exprStartsWithDeref() const {
490508
}
491509

492510
VarDecl *DebugValueInst::getDecl() const {
493-
return getLoc().getAsASTNode<VarDecl>();
511+
return getVarLoc().getAsASTNode<VarDecl>();
494512
}
495513

496514
VarDecl *SILDebugVariable::getDecl() const {

lib/SIL/Verifier/MemoryLifetimeVerifier.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -749,8 +749,7 @@ void MemoryLifetimeVerifier::checkBlock(SILBasicBlock *block, Bits &bits) {
749749
// an alloc_stack), which don't have any `op_deref` in its
750750
// di-expression, because that memory doesn't need to be initialized
751751
// when `debug_value` is referencing it.
752-
if (cast<DebugValueInst>(&I)->hasAddrVal() &&
753-
cast<DebugValueInst>(&I)->exprStartsWithDeref())
752+
if (!DebugValueInst::hasAddrVal(&I))
754753
requireBitsSet(bits, I.getOperand(0), &I);
755754
break;
756755
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;

0 commit comments

Comments
 (0)