Skip to content

Commit 9a8f2ed

Browse files
committed
[SILOptimizer][DebugInfo] Preliminary support for DIExpression in SROA and Mem2Reg
SROA and Mem2Reg now can leverage DIExpression -- op_fragment, more specifically -- to generate correct debug info for optimized SIL. Some important highlights: - The new swift::salvageDebugInfo, similar to llvm::salvageDebugInfo, tries to restore / transfer debug info from a deleted instruction. Currently I only implemented this for store instruction whose destination is an alloc_stack value. - Since we now have source-variable-specific SIL location inside a `debug_value` instruction (and its friends), this patch teaches SILCloner and SILInliner to remap the debug scope there in addition to debug scope of the instruction. - DCE now does not remove `debug_value` instruction whose associating with a function argument SSA value that is not used elsewhere. Since that SSA value will not disappear so we should keep the debug info.
1 parent e63632f commit 9a8f2ed

25 files changed

+373
-69
lines changed

include/swift/SIL/DebugUtils.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,24 @@ struct DebugVarCarryingInst {
308308
}
309309
llvm_unreachable("covered switch");
310310
}
311+
312+
void setDebugVarScope(const SILDebugScope *NewDS) {
313+
switch (kind) {
314+
case Kind::Invalid:
315+
llvm_unreachable("Invalid?!");
316+
case Kind::DebugValue:
317+
cast<DebugValueInst>(inst)->setDebugVarScope(NewDS);
318+
break;
319+
case Kind::DebugValueAddr:
320+
cast<DebugValueAddrInst>(inst)->setDebugVarScope(NewDS);
321+
break;
322+
case Kind::AllocStack:
323+
cast<AllocStackInst>(inst)->setDebugVarScope(NewDS);
324+
break;
325+
case Kind::AllocBox:
326+
llvm_unreachable("Not implemented");
327+
}
328+
}
311329
};
312330

313331
} // end namespace swift

include/swift/SIL/SILCloner.h

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "swift/AST/ProtocolConformance.h"
2121
#include "swift/SIL/BasicBlockUtils.h"
22+
#include "swift/SIL/DebugUtils.h"
2223
#include "swift/SIL/Dominance.h"
2324
#include "swift/SIL/SILBuilder.h"
2425
#include "swift/SIL/SILDebugScope.h"
@@ -245,6 +246,16 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
245246
registerOpenedExistentialRemapping(archetypeTy, replacementTy);
246247
}
247248

249+
// SILCloner will take care of debug scope on the instruction
250+
// and this helper will remap the auxiliary debug scope too, if there is any.
251+
void remapDebugVarInfo(DebugVarCarryingInst DbgVarInst) {
252+
if (!DbgVarInst)
253+
return;
254+
auto VarInfo = DbgVarInst.getVarInfo();
255+
if (VarInfo && VarInfo->Scope)
256+
DbgVarInst.setDebugVarScope(getOpScope(VarInfo->Scope));
257+
}
258+
248259
ProtocolConformanceRef getOpConformance(Type ty,
249260
ProtocolConformanceRef conformance) {
250261
// If we have open existentials to substitute, do so now.
@@ -748,9 +759,11 @@ SILCloner<ImplClass>::visitAllocStackInst(AllocStackInst *Inst) {
748759
Loc = MandatoryInlinedLocation::getAutoGeneratedLocation();
749760
VarInfo = None;
750761
}
751-
recordClonedInstruction(Inst, getBuilder().createAllocStack(
752-
Loc, getOpType(Inst->getElementType()),
753-
VarInfo, Inst->hasDynamicLifetime()));
762+
auto *NewInst =
763+
getBuilder().createAllocStack(Loc, getOpType(Inst->getElementType()),
764+
VarInfo, Inst->hasDynamicLifetime());
765+
remapDebugVarInfo(DebugVarCarryingInst(NewInst));
766+
recordClonedInstruction(Inst, NewInst);
754767
}
755768

756769
template<typename ImplClass>
@@ -1232,12 +1245,13 @@ SILCloner<ImplClass>::visitDebugValueInst(DebugValueInst *Inst) {
12321245
return;
12331246

12341247
// Since we want the debug info to survive, we do not remap the location here.
1248+
SILDebugVariable VarInfo = *Inst->getVarInfo();
12351249
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1236-
recordClonedInstruction(
1237-
Inst, getBuilder().createDebugValue(Inst->getLoc(),
1238-
getOpValue(Inst->getOperand()),
1239-
*Inst->getVarInfo(),
1240-
Inst->poisonRefs()));
1250+
auto *NewInst = getBuilder().createDebugValue(Inst->getLoc(),
1251+
getOpValue(Inst->getOperand()),
1252+
VarInfo, Inst->poisonRefs());
1253+
remapDebugVarInfo(DebugVarCarryingInst(NewInst));
1254+
recordClonedInstruction(Inst, NewInst);
12411255
}
12421256
template<typename ImplClass>
12431257
void
@@ -1249,11 +1263,13 @@ SILCloner<ImplClass>::visitDebugValueAddrInst(DebugValueAddrInst *Inst) {
12491263
return;
12501264

12511265
// Do not remap the location for a debug Instruction.
1266+
SILDebugVariable VarInfo = *Inst->getVarInfo();
12521267
SILValue OpValue = getOpValue(Inst->getOperand());
12531268
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1254-
recordClonedInstruction(
1255-
Inst, getBuilder().createDebugValueAddr(Inst->getLoc(), OpValue,
1256-
*Inst->getVarInfo()));
1269+
auto *NewInst = getBuilder().createDebugValueAddr(Inst->getLoc(), OpValue,
1270+
*Inst->getVarInfo());
1271+
remapDebugVarInfo(DebugVarCarryingInst(NewInst));
1272+
recordClonedInstruction(Inst, NewInst);
12571273
}
12581274

12591275
#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \

include/swift/SIL/SILDebugInfoExpression.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ class SILDebugInfoExpression {
123123
explicit SILDebugInfoExpression(llvm::ArrayRef<SILDIExprElement> EL)
124124
: Elements(EL.begin(), EL.end()) {}
125125

126+
void clear() { Elements.clear(); }
127+
126128
size_t getNumElements() const { return Elements.size(); }
127129

128130
using iterator = typename decltype(Elements)::iterator;
@@ -151,6 +153,15 @@ class SILDebugInfoExpression {
151153
Elements.push_back(Element);
152154
}
153155

156+
void appendElements(llvm::ArrayRef<SILDIExprElement> NewElements) {
157+
if (NewElements.size())
158+
Elements.append(NewElements.begin(), NewElements.end());
159+
}
160+
161+
void append(const SILDebugInfoExpression &Tail) {
162+
appendElements(Tail.Elements);
163+
}
164+
154165
/// The iterator for SILDIExprOperand
155166
class op_iterator {
156167
friend class SILDebugInfoExpression;
@@ -208,6 +219,9 @@ class SILDebugInfoExpression {
208219

209220
/// Return true if this expression is not empty
210221
inline operator bool() const { return Elements.size(); }
222+
223+
/// Create a op_fragment expression
224+
static SILDebugInfoExpression createFragment(VarDecl *Field);
211225
};
212226
} // end namespace swift
213227
#endif

include/swift/SIL/SILInstruction.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1732,6 +1732,10 @@ struct SILDebugVariable {
17321732
const SILDebugScope *Scope;
17331733
SILDebugInfoExpression DIExpr;
17341734

1735+
// Use vanilla copy ctor / operator
1736+
SILDebugVariable(const SILDebugVariable &) = default;
1737+
SILDebugVariable &operator=(const SILDebugVariable &) = default;
1738+
17351739
SILDebugVariable()
17361740
: ArgNo(0), Constant(false), Implicit(false), Scope(nullptr) {}
17371741
SILDebugVariable(bool Constant, uint16_t ArgNo)
@@ -1744,6 +1748,10 @@ struct SILDebugVariable {
17441748
: Name(Name), ArgNo(ArgNo), Constant(Constant), Implicit(IsImplicit),
17451749
Type(AuxType), Loc(DeclLoc), Scope(DeclScope), DIExpr(ExprElements) {}
17461750

1751+
/// Created from either AllocStack or AllocBox instruction
1752+
static Optional<SILDebugVariable>
1753+
createFromAllocation(const AllocationInst *AI);
1754+
17471755
// We're not comparing DIExpr here because strictly speaking,
17481756
// DIExpr is not part of the debug variable. We simply piggyback
17491757
// it in this class so that's it's easier to carry DIExpr around.
@@ -1962,6 +1970,11 @@ class AllocStackInst final
19621970
SILNode::Bits.AllocStackInst.VarInfo = VI.getRawValue();
19631971
}
19641972

1973+
void setDebugVarScope(const SILDebugScope *NewDS) {
1974+
if (hasAuxDebugScope())
1975+
*getTrailingObjects<const SILDebugScope *>() = NewDS;
1976+
}
1977+
19651978
/// getElementType - Get the type of the allocated memory (as opposed to the
19661979
/// type of the instruction itself, which will be an address type).
19671980
SILType getElementType() const {
@@ -4681,6 +4694,11 @@ class DebugValueInst final
46814694
VarDeclLoc, VarDeclScope, DIExprElements);
46824695
}
46834696

4697+
void setDebugVarScope(const SILDebugScope *NewDS) {
4698+
if (hasAuxDebugScope())
4699+
*getTrailingObjects<const SILDebugScope *>() = NewDS;
4700+
}
4701+
46844702
/// True if all references within this debug value will be overwritten with a
46854703
/// poison sentinel at this point in the program. This is used in debug builds
46864704
/// when shortening non-trivial value lifetimes to ensure the debugger cannot
@@ -4741,7 +4759,12 @@ class DebugValueAddrInst final
47414759

47424760
return VarInfo.get(getDecl(), getTrailingObjects<char>(), AuxVarType,
47434761
VarDeclLoc, VarDeclScope, DIExprElements);
4744-
};
4762+
}
4763+
4764+
void setDebugVarScope(const SILDebugScope *NewDS) {
4765+
if (hasAuxDebugScope())
4766+
*getTrailingObjects<const SILDebugScope *>() = NewDS;
4767+
}
47454768
};
47464769

47474770
/// An abstract class representing a load from some kind of reference storage.

include/swift/SILOptimizer/Utils/DebugOptUtils.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ inline void deleteAllDebugUses(SILInstruction *inst,
4343
}
4444
}
4545

46+
/// Transfer debug info associated with (the result of) \p I to a
47+
/// new `debug_value` or `debug_value_addr` instruction before \p I is
48+
/// deleted.
49+
void salvageDebugInfo(SILInstruction *I);
50+
4651
/// Erases the instruction \p I from it's parent block and deletes it, including
4752
/// all debug instructions which use \p I.
4853
/// Precondition: The instruction may only have debug instructions as uses.
@@ -76,6 +81,7 @@ eraseFromParentWithDebugInsts(SILInstruction *inst,
7681
// Just matching what eraseFromParentWithDebugInsts is today.
7782
if (nextII == inst->getIterator())
7883
++nextII;
84+
swift::salvageDebugInfo(inst);
7985
callbacks.deleteInst(inst, false /*do not notify*/);
8086
return nextII;
8187
}

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,11 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
191191
void emitArtificialFunction(IRBuilder &Builder, llvm::Function *Fn,
192192
SILType SILTy);
193193

194-
void handleFragmentDIExpr(const SILDIExprOperand &CurDIExprOp,
194+
/// Return false if we fail to create the right DW_OP_LLVM_fragment operand.
195+
bool handleFragmentDIExpr(const SILDIExprOperand &CurDIExprOp,
195196
SmallVectorImpl<uint64_t> &Operands);
196-
void buildDebugInfoExpression(const SILDebugVariable &VarInfo,
197+
/// Return false if we fail to create the desired !DIExpression.
198+
bool buildDebugInfoExpression(const SILDebugVariable &VarInfo,
197199
SmallVectorImpl<uint64_t> &Operands);
198200

199201
void emitVariableDeclaration(IRBuilder &Builder,
@@ -2336,9 +2338,8 @@ void IRGenDebugInfoImpl::emitArtificialFunction(IRBuilder &Builder,
23362338
setCurrentLoc(Builder, Scope, ALoc);
23372339
}
23382340

2339-
void IRGenDebugInfoImpl::handleFragmentDIExpr(
2340-
const SILDIExprOperand &CurDIExprOp,
2341-
SmallVectorImpl<uint64_t> &Operands) {
2341+
bool IRGenDebugInfoImpl::handleFragmentDIExpr(
2342+
const SILDIExprOperand &CurDIExprOp, SmallVectorImpl<uint64_t> &Operands) {
23422343
assert(CurDIExprOp.getOperator() == SILDIExprOperator::Fragment);
23432344
// Expecting a VarDecl that points to a field in an struct
23442345
auto DIExprArgs = CurDIExprOp.args();
@@ -2348,14 +2349,22 @@ void IRGenDebugInfoImpl::handleFragmentDIExpr(
23482349
"DIExprOperator::Fragment");
23492350
// Translate the based type
23502351
DeclContext *ParentDecl = VD->getDeclContext();
2352+
assert(ParentDecl && "VarDecl has no parent context?");
23512353
SILType ParentSILType =
23522354
IGM.getLoweredType(ParentDecl->getDeclaredTypeInContext());
23532355
// Retrieve the offset & size of the field
23542356
llvm::Constant *Offset =
23552357
emitPhysicalStructMemberFixedOffset(IGM, ParentSILType, VD);
2356-
llvm::Type *FieldTy =
2357-
getPhysicalStructFieldTypeInfo(IGM, ParentSILType, VD)->getStorageType();
2358-
assert(Offset && FieldTy && "Non-fixed type?");
2358+
auto *FieldTypeInfo = getPhysicalStructFieldTypeInfo(IGM, ParentSILType, VD);
2359+
// FIXME: This will only happen if IRGen hasn't processed ParentSILType
2360+
// (into its own representation) but we probably should ask IRGen to process
2361+
// it right now.
2362+
if (!FieldTypeInfo)
2363+
return false;
2364+
llvm::Type *FieldTy = FieldTypeInfo->getStorageType();
2365+
// Doesn't support non-fixed type right now
2366+
if (!Offset || !FieldTy)
2367+
return false;
23592368

23602369
uint64_t SizeOfByte = CI.getTargetInfo().getCharWidth();
23612370
uint64_t SizeInBits = IGM.DataLayout.getTypeSizeInBits(FieldTy);
@@ -2366,22 +2375,26 @@ void IRGenDebugInfoImpl::handleFragmentDIExpr(
23662375
Operands.push_back(llvm::dwarf::DW_OP_LLVM_fragment);
23672376
Operands.push_back(OffsetInBits);
23682377
Operands.push_back(SizeInBits);
2378+
2379+
return true;
23692380
}
23702381

2371-
void IRGenDebugInfoImpl::buildDebugInfoExpression(
2382+
bool IRGenDebugInfoImpl::buildDebugInfoExpression(
23722383
const SILDebugVariable &VarInfo, SmallVectorImpl<uint64_t> &Operands) {
23732384
assert(VarInfo.DIExpr && "SIL debug info expression not found");
23742385

23752386
const auto &DIExpr = VarInfo.DIExpr;
23762387
for (const SILDIExprOperand &ExprOperand : DIExpr.operands()) {
23772388
switch (ExprOperand.getOperator()) {
23782389
case SILDIExprOperator::Fragment:
2379-
handleFragmentDIExpr(ExprOperand, Operands);
2390+
if (!handleFragmentDIExpr(ExprOperand, Operands))
2391+
return false;
23802392
break;
23812393
default:
2382-
llvm_unreachable("Unrecoginized operator");
2394+
llvm_unreachable("Unrecognized operator");
23832395
}
23842396
}
2397+
return true;
23852398
}
23862399

23872400
void IRGenDebugInfoImpl::emitVariableDeclaration(
@@ -2455,7 +2468,8 @@ void IRGenDebugInfoImpl::emitVariableDeclaration(
24552468
[&VarInfo, this](llvm::DIExpression *DIExpr) -> llvm::DIExpression * {
24562469
if (VarInfo.DIExpr) {
24572470
llvm::SmallVector<uint64_t, 2> Operands;
2458-
buildDebugInfoExpression(VarInfo, Operands);
2471+
if (!buildDebugInfoExpression(VarInfo, Operands))
2472+
return nullptr;
24592473
if (Operands.size())
24602474
return llvm::DIExpression::append(DIExpr, Operands);
24612475
}
@@ -2493,22 +2507,24 @@ void IRGenDebugInfoImpl::emitVariableDeclaration(
24932507
Operands.push_back(SizeInBits);
24942508
}
24952509
llvm::DIExpression *DIExpr = DBuilder.createExpression(Operands);
2496-
emitDbgIntrinsic(Builder, Piece, Var,
2497-
// DW_OP_LLVM_fragment must be the last part of an DIExpr
2498-
// so we can't append more if IsPiece is true.
2499-
IsPiece ? DIExpr : appendDIExpression(DIExpr), DInstLine,
2500-
DInstLoc.column, Scope, DS,
2501-
Indirection == CoroDirectValue ||
2502-
Indirection == CoroIndirectValue);
2510+
// DW_OP_LLVM_fragment must be the last part of an DIExpr
2511+
// so we can't append more if IsPiece is true.
2512+
if (!IsPiece)
2513+
DIExpr = appendDIExpression(DIExpr);
2514+
if (DIExpr)
2515+
emitDbgIntrinsic(
2516+
Builder, Piece, Var, DIExpr, DInstLine, DInstLoc.column, Scope, DS,
2517+
Indirection == CoroDirectValue || Indirection == CoroIndirectValue);
25032518
}
25042519

25052520
// Emit locationless intrinsic for variables that were optimized away.
2506-
if (Storage.empty())
2507-
emitDbgIntrinsic(Builder, llvm::ConstantInt::get(IGM.Int64Ty, 0), Var,
2508-
appendDIExpression(DBuilder.createExpression()), DInstLine,
2509-
DInstLoc.column, Scope, DS,
2510-
Indirection == CoroDirectValue ||
2511-
Indirection == CoroIndirectValue);
2521+
if (Storage.empty()) {
2522+
if (auto *DIExpr = appendDIExpression(DBuilder.createExpression()))
2523+
emitDbgIntrinsic(Builder, llvm::ConstantInt::get(IGM.Int64Ty, 0), Var,
2524+
DIExpr, DInstLine, DInstLoc.column, Scope, DS,
2525+
Indirection == CoroDirectValue ||
2526+
Indirection == CoroIndirectValue);
2527+
}
25122528
}
25132529

25142530
void IRGenDebugInfoImpl::emitDbgIntrinsic(
@@ -2554,7 +2570,19 @@ void IRGenDebugInfoImpl::emitDbgIntrinsic(
25542570
DBuilder.insertDeclare(Storage, Var, Expr, DL, &EntryBlock);
25552571
} else {
25562572
// Insert a dbg.value at the current insertion point.
2557-
DBuilder.insertDbgValueIntrinsic(Storage, Var, Expr, DL, BB);
2573+
if (isa<llvm::Argument>(Storage) && !Var->getArg() &&
2574+
BB->getFirstNonPHIOrDbg())
2575+
// SelectionDAGISel only generates debug info for a dbg.value
2576+
// that is associated with a llvm::Argument if either its !DIVariable
2577+
// is marked as argument or there is no non-debug intrinsic instruction
2578+
// before it. So In the case of associating a llvm::Argument with a
2579+
// non-argument debug variable -- usually via a !DIExpression -- we
2580+
// need to make sure that dbg.value is before any non-phi / no-dbg
2581+
// instruction.
2582+
DBuilder.insertDbgValueIntrinsic(Storage, Var, Expr, DL,
2583+
BB->getFirstNonPHIOrDbg());
2584+
else
2585+
DBuilder.insertDbgValueIntrinsic(Storage, Var, Expr, DL, BB);
25582586
}
25592587
}
25602588

lib/IRGen/IRGenSIL.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4752,8 +4752,7 @@ void IRGenSILFunction::visitDebugValueInst(DebugValueInst *i) {
47524752
if (VarDecl *Decl = i->getDecl()) {
47534753
DbgTy = DebugTypeInfo::getLocalVariable(
47544754
Decl, RealTy, getTypeInfo(SILVal->getType()));
4755-
} else if (i->getFunction()->isBare() && !SILTy.hasArchetype() &&
4756-
!VarInfo->Name.empty()) {
4755+
} else if (!SILTy.hasArchetype() && !VarInfo->Name.empty()) {
47574756
// Preliminary support for .sil debug information.
47584757
DbgTy = DebugTypeInfo::getFromTypeInfo(RealTy, getTypeInfo(SILTy));
47594758
} else

lib/SIL/IR/SILBasicBlock.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,15 @@ transferNodesFromList(llvm::ilist_traits<SILBasicBlock> &SrcTraits,
292292
First->Parent = Parent;
293293
First->index = -1;
294294
First->lastInitializedBitfieldID = 0;
295-
for (auto &II : *First)
295+
for (auto &II : *First) {
296296
II.setDebugScope(ScopeCloner.getOrCreateClonedScope(II.getDebugScope()));
297+
// Special handling for SILDebugVariable.
298+
if (auto DVI = DebugVarCarryingInst(&II))
299+
if (auto VarInfo = DVI.getVarInfo())
300+
if (VarInfo->Scope)
301+
DVI.setDebugVarScope(
302+
ScopeCloner.getOrCreateClonedScope(VarInfo->Scope));
303+
}
297304
}
298305
}
299306

0 commit comments

Comments
 (0)