Skip to content

Commit b363bbd

Browse files
committed
[IRGen][Patch 2/2] Add IRGen support for SIL DIExpression
This patch is primarily doing two things: - Teach IRGen for some of the instructions to generate debug info based on SILDebugVariable rather than AST node, which is not always available when reading from SIL. - Generate corresponding `llvm.dbg.*` intrinsics and `!DIExpression` from the newly added SIL DIExpression.
1 parent 377bdfa commit b363bbd

File tree

6 files changed

+179
-46
lines changed

6 files changed

+179
-46
lines changed

lib/IRGen/GenStruct.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,13 @@ namespace {
216216
return nullptr;
217217
}
218218

219+
const TypeInfo *getFieldTypeInfo(IRGenModule &IGM, VarDecl *field) const {
220+
auto &fieldInfo = getFieldInfo(field);
221+
if (fieldInfo.isEmpty())
222+
return nullptr;
223+
return &fieldInfo.getTypeInfo();
224+
}
225+
219226
MemberAccessStrategy getFieldAccessStrategy(IRGenModule &IGM,
220227
SILType T, VarDecl *field) const {
221228
auto &fieldInfo = getFieldInfo(field);
@@ -1137,6 +1144,12 @@ Optional<unsigned> irgen::getPhysicalStructFieldIndex(IRGenModule &IGM,
11371144
FOR_STRUCT_IMPL(IGM, baseType, getFieldIndexIfNotEmpty, field);
11381145
}
11391146

1147+
const TypeInfo *irgen::getPhysicalStructFieldTypeInfo(IRGenModule &IGM,
1148+
SILType baseType,
1149+
VarDecl *field) {
1150+
FOR_STRUCT_IMPL(IGM, baseType, getFieldTypeInfo, field);
1151+
}
1152+
11401153
void IRGenModule::emitStructDecl(StructDecl *st) {
11411154
if (!IRGen.hasLazyMetadata(st)) {
11421155
emitStructMetadata(*this, st);

lib/IRGen/GenStruct.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ namespace irgen {
3434
class IRGenFunction;
3535
class IRGenModule;
3636
class MemberAccessStrategy;
37-
37+
class TypeInfo;
38+
3839
Address projectPhysicalStructMemberAddress(IRGenFunction &IGF,
3940
Address base,
4041
SILType baseType,
@@ -58,6 +59,10 @@ namespace irgen {
5859
getPhysicalStructMemberAccessStrategy(IRGenModule &IGM,
5960
SILType baseType, VarDecl *field);
6061

62+
const TypeInfo *getPhysicalStructFieldTypeInfo(IRGenModule &IGM,
63+
SILType baseType,
64+
VarDecl *field);
65+
6166
/// Returns the index of the element in the llvm struct type which represents
6267
/// \p field in \p baseType.
6368
///
@@ -66,7 +71,6 @@ namespace irgen {
6671
llvm::Optional<unsigned> getPhysicalStructFieldIndex(IRGenModule &IGM,
6772
SILType baseType,
6873
VarDecl *field);
69-
7074
} // end namespace irgen
7175
} // end namespace swift
7276

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 101 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#define DEBUG_TYPE "debug-info"
1818
#include "IRGenDebugInfo.h"
1919
#include "GenOpaque.h"
20+
#include "GenStruct.h"
2021
#include "GenType.h"
2122
#include "swift/AST/ASTMangler.h"
2223
#include "swift/AST/Expr.h"
@@ -189,6 +190,12 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
189190
llvm::DISubprogram *emitFunction(SILFunction &SILFn, llvm::Function *Fn);
190191
void emitArtificialFunction(IRBuilder &Builder, llvm::Function *Fn,
191192
SILType SILTy);
193+
194+
void handleFragmentDIExpr(const SILDIExprOperand &CurDIExprOp,
195+
SmallVectorImpl<uint64_t> &Operands);
196+
void buildDebugInfoExpression(const SILDebugVariable &VarInfo,
197+
SmallVectorImpl<uint64_t> &Operands);
198+
192199
void emitVariableDeclaration(IRBuilder &Builder,
193200
ArrayRef<llvm::Value *> Storage,
194201
DebugTypeInfo Ty, const SILDebugScope *DS,
@@ -2330,10 +2337,59 @@ void IRGenDebugInfoImpl::emitArtificialFunction(IRBuilder &Builder,
23302337
setCurrentLoc(Builder, Scope, ALoc);
23312338
}
23322339

2340+
void IRGenDebugInfoImpl::handleFragmentDIExpr(
2341+
const SILDIExprOperand &CurDIExprOp,
2342+
SmallVectorImpl<uint64_t> &Operands) {
2343+
assert(CurDIExprOp.getOperator() == SILDIExprOperator::Fragment);
2344+
// Expecting a VarDecl that points to a field in an struct
2345+
auto DIExprArgs = CurDIExprOp.args();
2346+
auto *VD = dyn_cast_or_null<VarDecl>(DIExprArgs.size()?
2347+
DIExprArgs[0].getAsDecl() : nullptr);
2348+
assert(VD && "Expecting a VarDecl as the operand for "
2349+
"DIExprOperator::Fragment");
2350+
// Translate the based type
2351+
DeclContext *ParentDecl = VD->getDeclContext();
2352+
SILType ParentSILType =
2353+
IGM.getLoweredType(ParentDecl->getDeclaredTypeInContext());
2354+
// Retrieve the offset & size of the field
2355+
llvm::Constant *Offset =
2356+
emitPhysicalStructMemberFixedOffset(IGM, ParentSILType, VD);
2357+
llvm::Type *FieldTy =
2358+
getPhysicalStructFieldTypeInfo(IGM, ParentSILType, VD)->getStorageType();
2359+
assert(Offset && FieldTy && "Non-fixed type?");
2360+
2361+
uint64_t SizeOfByte = CI.getTargetInfo().getCharWidth();
2362+
uint64_t SizeInBits = IGM.DataLayout.getTypeSizeInBits(FieldTy);
2363+
uint64_t OffsetInBits =
2364+
Offset->getUniqueInteger().getLimitedValue() * SizeOfByte;
2365+
2366+
// Translate to LLVM dbg intrinsic operands
2367+
Operands.push_back(llvm::dwarf::DW_OP_LLVM_fragment);
2368+
Operands.push_back(OffsetInBits);
2369+
Operands.push_back(SizeInBits);
2370+
}
2371+
2372+
void IRGenDebugInfoImpl::buildDebugInfoExpression(
2373+
const SILDebugVariable &VarInfo, SmallVectorImpl<uint64_t> &Operands) {
2374+
assert(VarInfo.DIExpr && "SIL debug info expression not found");
2375+
2376+
const auto &DIExpr = VarInfo.DIExpr;
2377+
for (const SILDIExprOperand &ExprOperand : DIExpr.operands()) {
2378+
switch (ExprOperand.getOperator()) {
2379+
case SILDIExprOperator::Fragment:
2380+
handleFragmentDIExpr(ExprOperand, Operands);
2381+
break;
2382+
default:
2383+
llvm_unreachable("Unrecoginized operator");
2384+
}
2385+
}
2386+
}
2387+
23332388
void IRGenDebugInfoImpl::emitVariableDeclaration(
23342389
IRBuilder &Builder, ArrayRef<llvm::Value *> Storage, DebugTypeInfo DbgTy,
2335-
const SILDebugScope *DS, Optional<SILLocation> VarLoc, SILDebugVariable VarInfo,
2336-
IndirectionKind Indirection, ArtificialKind Artificial) {
2390+
const SILDebugScope *DS, Optional<SILLocation> DbgInstLoc,
2391+
SILDebugVariable VarInfo, IndirectionKind Indirection,
2392+
ArtificialKind Artificial) {
23372393
assert(DS && "variable has no scope");
23382394

23392395
if (Opts.DebugInfoLevel <= IRGenDebugInfoLevel::LineTables)
@@ -2348,7 +2404,7 @@ void IRGenDebugInfoImpl::emitVariableDeclaration(
23482404

23492405
auto *Scope = dyn_cast_or_null<llvm::DILocalScope>(getOrCreateScope(DS));
23502406
assert(Scope && "variable has no local scope");
2351-
auto Loc = getStartLocation(VarLoc);
2407+
auto DInstLoc = getStartLocation(DbgInstLoc);
23522408

23532409
// FIXME: this should be the scope of the type's declaration.
23542410
// If this is an argument, attach it to the current function scope.
@@ -2363,10 +2419,11 @@ void IRGenDebugInfoImpl::emitVariableDeclaration(
23632419
if (VarInfo.Constant)
23642420
DITy = DBuilder.createQualifiedType(llvm::dwarf::DW_TAG_const_type, DITy);
23652421

2366-
unsigned Line = Loc.line;
2422+
unsigned DInstLine = DInstLoc.line;
23672423

23682424
// Self is always an artificial argument, so are variables without location.
2369-
if (!Line || (VarInfo.ArgNo > 0 && VarInfo.Name == IGM.Context.Id_self.str()))
2425+
if (!DInstLine ||
2426+
(VarInfo.ArgNo > 0 && VarInfo.Name == IGM.Context.Id_self.str()))
23702427
Artificial = ArtificialValue;
23712428

23722429
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
@@ -2376,12 +2433,35 @@ void IRGenDebugInfoImpl::emitVariableDeclaration(
23762433
// This could be Opts.Optimize if we would also unique DIVariables here.
23772434
bool Optimized = false;
23782435
// Create the descriptor for the variable.
2436+
unsigned DVarLine = DInstLine;
2437+
if (VarInfo.Loc) {
2438+
auto DVarLoc = getStartLocation(VarInfo.Loc);
2439+
DVarLine = DVarLoc.line;
2440+
}
2441+
llvm::DIScope *VarScope = Scope;
2442+
if (VarInfo.Scope) {
2443+
if (auto *VS = dyn_cast_or_null<llvm::DILocalScope>(
2444+
getOrCreateScope(VarInfo.Scope)))
2445+
VarScope = VS;
2446+
}
23792447
llvm::DILocalVariable *Var =
23802448
(VarInfo.ArgNo > 0)
2381-
? DBuilder.createParameterVariable(Scope, VarInfo.Name, VarInfo.ArgNo,
2382-
Unit, Line, DITy, Optimized, Flags)
2383-
: DBuilder.createAutoVariable(Scope, VarInfo.Name, Unit, Line, DITy,
2384-
Optimized, Flags);
2449+
? DBuilder.createParameterVariable(VarScope, VarInfo.Name,
2450+
VarInfo.ArgNo, Unit, DVarLine,
2451+
DITy, Optimized, Flags)
2452+
: DBuilder.createAutoVariable(VarScope, VarInfo.Name, Unit, DVarLine,
2453+
DITy, Optimized, Flags);
2454+
2455+
auto appendDIExpression =
2456+
[&VarInfo, this](llvm::DIExpression *DIExpr) -> llvm::DIExpression * {
2457+
if (VarInfo.DIExpr) {
2458+
llvm::SmallVector<uint64_t, 2> Operands;
2459+
buildDebugInfoExpression(VarInfo, Operands);
2460+
if (Operands.size())
2461+
return llvm::DIExpression::append(DIExpr, Operands);
2462+
}
2463+
return DIExpr;
2464+
};
23852465

23862466
// Running variables for the current/previous piece.
23872467
bool IsPiece = Storage.size() > 1;
@@ -2413,16 +2493,21 @@ void IRGenDebugInfoImpl::emitVariableDeclaration(
24132493
Operands.push_back(OffsetInBits);
24142494
Operands.push_back(SizeInBits);
24152495
}
2416-
emitDbgIntrinsic(Builder, Piece, Var, DBuilder.createExpression(Operands),
2417-
Line, Loc.column, Scope, DS,
2418-
Indirection == CoroDirectValue ||
2419-
Indirection == CoroIndirectValue);
2496+
llvm::DIExpression *DIExpr = DBuilder.createExpression(Operands);
2497+
emitDbgIntrinsic(
2498+
Builder, Piece, Var,
2499+
// DW_OP_LLVM_fragment must be the last part of an DIExpr
2500+
// so we can't append more if IsPiece is true.
2501+
Operands.empty() || IsPiece ? DIExpr : appendDIExpression(DIExpr),
2502+
DInstLine, DInstLoc.column, Scope, DS,
2503+
Indirection == CoroDirectValue || Indirection == CoroIndirectValue);
24202504
}
24212505

24222506
// Emit locationless intrinsic for variables that were optimized away.
24232507
if (Storage.empty())
24242508
emitDbgIntrinsic(Builder, llvm::ConstantInt::get(IGM.Int64Ty, 0), Var,
2425-
DBuilder.createExpression(), Line, Loc.column, Scope, DS,
2509+
appendDIExpression(DBuilder.createExpression()), DInstLine,
2510+
DInstLoc.column, Scope, DS,
24262511
Indirection == CoroDirectValue ||
24272512
Indirection == CoroIndirectValue);
24282513
}
@@ -2438,7 +2523,8 @@ void IRGenDebugInfoImpl::emitDbgIntrinsic(
24382523
auto *BB = Builder.GetInsertBlock();
24392524

24402525
// An alloca may only be described by exactly one dbg.declare.
2441-
if (isa<llvm::AllocaInst>(Storage) && !llvm::FindDbgAddrUses(Storage).empty())
2526+
if (isa<llvm::AllocaInst>(Storage) &&
2527+
!llvm::FindDbgDeclareUses(Storage).empty())
24422528
return;
24432529

24442530
// A dbg.declare is only meaningful if there is a single alloca for

lib/IRGen/IRGenSIL.cpp

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4734,8 +4734,13 @@ void IRGenSILFunction::visitDebugValueInst(DebugValueInst *i) {
47344734
bool IsAnonymous = false;
47354735
VarInfo->Name = getVarName(i, IsAnonymous);
47364736
DebugTypeInfo DbgTy;
4737-
SILType SILTy = SILVal->getType();
4738-
auto RealTy = SILVal->getType().getASTType();
4737+
SILType SILTy;
4738+
if (auto MaybeSILTy = VarInfo->Type)
4739+
// If there is auxiliary type info, use it
4740+
SILTy = *MaybeSILTy;
4741+
else
4742+
SILTy = SILVal->getType();
4743+
auto RealTy = SILTy.getASTType();
47394744
if (VarDecl *Decl = i->getDecl()) {
47404745
DbgTy = DebugTypeInfo::getLocalVariable(
47414746
Decl, RealTy, getTypeInfo(SILVal->getType()));
@@ -4765,10 +4770,6 @@ void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) {
47654770
if (i->getDebugScope()->getInlinedFunction()->isTransparent())
47664771
return;
47674772

4768-
VarDecl *Decl = i->getDecl();
4769-
if (!Decl)
4770-
return;
4771-
47724773
auto SILVal = i->getOperand();
47734774
if (isa<SILUndef>(SILVal))
47744775
return;
@@ -4781,7 +4782,12 @@ void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) {
47814782
(IsLoadablyByAddress) ? DirectValue : IndirectValue;
47824783
VarInfo->Name = getVarName(i, IsAnonymous);
47834784
auto *Addr = getLoweredAddress(SILVal).getAddress();
4784-
SILType SILTy = SILVal->getType();
4785+
SILType SILTy;
4786+
if (auto MaybeSILTy = VarInfo->Type)
4787+
// If there is auxiliary type info, use it
4788+
SILTy = *MaybeSILTy;
4789+
else
4790+
SILTy = SILVal->getType();
47854791
auto RealType = SILTy.getASTType();
47864792
if (CurSILFn->isAsync() && !i->getDebugScope()->InlinedCallSite) {
47874793
Indirection = CoroIndirectValue;
@@ -4796,8 +4802,17 @@ void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) {
47964802
}
47974803
}
47984804

4799-
auto DbgTy = DebugTypeInfo::getLocalVariable(
4800-
Decl, RealType, getTypeInfo(SILVal->getType()));
4805+
DebugTypeInfo DbgTy;
4806+
if (VarDecl *Decl = i->getDecl())
4807+
DbgTy = DebugTypeInfo::getLocalVariable(Decl, RealType,
4808+
getTypeInfo(SILVal->getType()));
4809+
else if (i->getFunction()->isBare() && !SILTy.hasArchetype() &&
4810+
!VarInfo->Name.empty())
4811+
// Handle the cases that read from a SIL file
4812+
DbgTy = DebugTypeInfo::getFromTypeInfo(RealType, getTypeInfo(SILTy));
4813+
else
4814+
return;
4815+
48014816
bindArchetypes(DbgTy.getType());
48024817
if (!IGM.DebugInfo)
48034818
return;
@@ -5128,18 +5143,26 @@ void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i,
51285143
InCoroContext(*CurSILFn, *i) ? CoroIndirectValue : IndirectValue;
51295144
}
51305145

5131-
if (!Decl)
5132-
return;
5133-
51345146
// Ignore compiler-generated patterns but not optional bindings.
5135-
if (auto *Pattern = Decl->getParentPattern())
5136-
if (Pattern->isImplicit() &&
5137-
Pattern->getKind() != PatternKind::OptionalSome)
5138-
return;
5147+
if (Decl) {
5148+
if (auto *Pattern = Decl->getParentPattern()) {
5149+
if (Pattern->isImplicit() &&
5150+
Pattern->getKind() != PatternKind::OptionalSome)
5151+
return;
5152+
}
5153+
}
51395154

51405155
SILType SILTy = i->getType();
51415156
auto RealType = SILTy.getASTType();
5142-
auto DbgTy = DebugTypeInfo::getLocalVariable(Decl, RealType, type);
5157+
DebugTypeInfo DbgTy;
5158+
if (Decl) {
5159+
DbgTy = DebugTypeInfo::getLocalVariable(Decl, RealType, type);
5160+
} else if (i->getFunction()->isBare() && !SILTy.hasArchetype() &&
5161+
!VarInfo->Name.empty()) {
5162+
DbgTy = DebugTypeInfo::getFromTypeInfo(RealType, getTypeInfo(SILTy));
5163+
} else
5164+
return;
5165+
51435166
// Async functions use the value of the artificial address.
51445167
auto shadow = addr;
51455168
if (CurSILFn->isAsync() && emitLifetimeExtendingUse(shadow) &&
@@ -5174,15 +5197,15 @@ void IRGenSILFunction::visitAllocStackInst(swift::AllocStackInst *i) {
51745197
Address addr = stackAddr.getAddress();
51755198

51765199
// Generate Debug Info.
5177-
if (!Decl)
5200+
if (!i->getVarInfo())
51785201
return;
51795202

5180-
assert(i->getVarInfo() && "alloc_stack without debug info");
5181-
5182-
Type Desugared = Decl->getType()->getDesugaredType();
5183-
if (Desugared->getClassOrBoundGenericClass() ||
5184-
Desugared->getStructOrBoundGenericStruct())
5185-
zeroInit(dyn_cast<llvm::AllocaInst>(addr.getAddress()));
5203+
if (Decl) {
5204+
Type Desugared = Decl->getType()->getDesugaredType();
5205+
if (Desugared->getClassOrBoundGenericClass() ||
5206+
Desugared->getStructOrBoundGenericStruct())
5207+
zeroInit(dyn_cast<llvm::AllocaInst>(addr.getAddress()));
5208+
}
51865209
emitDebugInfoForAllocStack(i, type, addr.getAddress());
51875210
}
51885211

test/DebugInfo/debug_info_expression.sil

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %target-swift-frontend %s -sil-verify-all -g -emit-sil -o - | %FileCheck %s
1+
// RUN: %target-swift-frontend %s -sil-verify-all -g -emit-sil -o - | %FileCheck --check-prefix=CHECK-SIL %s
2+
// RUN: %target-swift-frontend -disable-debugger-shadow-copies -primary-file %s -emit-ir -g -o - | %FileCheck %s
23
import Builtin
34
import Swift
45

@@ -12,11 +13,17 @@ sil_scope 1 { loc "file.swift":7:6 parent @test_fragment : $@convention(thin) ()
1213
sil hidden @test_fragment : $@convention(thin) () -> () {
1314
bb0:
1415
%2 = alloc_stack $MyStruct, var, name "my_struct", loc "file.swift":8:9, scope 1
16+
// CHECK: %[[MY_STRUCT:.+]] = alloca %{{.*}}MyStruct
17+
// CHECK: llvm.dbg.declare(metadata {{.*}}* %[[MY_STRUCT]], metadata ![[VAR_DECL_MD:[0-9]+]]
1518
%3 = struct_element_addr %2 : $*MyStruct, #MyStruct.x, loc "file.swift":9:17, scope 1
16-
// CHECK: debug_value_addr %{{[0-9]+}} : $*Builtin.Int64
17-
// CHECK-SAME: (name "my_struct", loc "file.swift":8:9, scope {{[0-9]+}})
18-
// CHECK-SAME type $MyStruct, expr op_fragment:#MyStruct.x
19+
// CHECK: %[[FIELD_X:.*]] = getelementptr {{.*}} %[[MY_STRUCT]]
20+
// CHECK-SIL: debug_value_addr %{{[0-9]+}} : $*Builtin.Int64
21+
// CHECK-SIL-SAME: (name "my_struct", loc "file.swift":8:9, scope {{[0-9]+}})
22+
// CHECK-SIL-SAME type $MyStruct, expr op_fragment:#MyStruct.x
1923
debug_value_addr %3 : $*Builtin.Int64, var, (name "my_struct", loc "file.swift":8:9, scope 1), type $MyStruct, expr op_fragment:#MyStruct.x, loc "file.swift":9:17, scope 1
24+
// CHECK: llvm.dbg.value(metadata {{.*}}* %[[FIELD_X]], metadata ![[VAR_DECL_MD]]
25+
// CHECK-SAME: !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 64)
26+
// CHECK-NOT: ), !dbg ![[VAR_DECL_MD]]
2027
dealloc_stack %2 : $*MyStruct
2128
%r = tuple()
2229
return %r : $()

test/IRGen/lifetime.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -gnone -emit-ir %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-cpu %s -DINT=i%target-ptrsize
1+
// RUN: %target-swift-frontend -disable-debugger-shadow-copies -gnone -emit-ir %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-cpu %s -DINT=i%target-ptrsize
22

33
// CHECK: [[OPAQUE:%swift.opaque]] = type opaque
44
// CHECK: [[TYPE:%swift.type]] = type

0 commit comments

Comments
 (0)