Skip to content

Commit 7cd787f

Browse files
committed
[DebugInfo] Emit debug info for witness tables
This change emits debug info for witness tables passed into generic functions when a generic type is constrained to a protocol. This information is required for LLDB's generic expression evaluator to work in such functions. rdar://104446865
1 parent 42f0b89 commit 7cd787f

File tree

5 files changed

+140
-23
lines changed

5 files changed

+140
-23
lines changed

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,16 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
279279
DebugTypeInfo DebugType,
280280
bool IsLocalToUnit,
281281
std::optional<SILLocation> Loc);
282+
283+
void emitArtificialVariable(IRGenFunction &IGF, llvm::Value *Metadata,
284+
StringRef Name, StringRef Identifier);
285+
282286
void emitTypeMetadata(IRGenFunction &IGF, llvm::Value *Metadata,
283287
unsigned Depth, unsigned Index, StringRef Name);
288+
289+
void emitWitnessTable(IRGenFunction &IGF, llvm::Value *Metadata,
290+
unsigned Depth, unsigned Index, ProtocolDecl *protocol);
291+
284292
void emitPackCountParameter(IRGenFunction &IGF, llvm::Value *Metadata,
285293
SILDebugVariable VarInfo);
286294

@@ -3700,9 +3708,10 @@ void IRGenDebugInfoImpl::emitGlobalVariableDeclaration(
37003708
Var->addDebugInfo(GV);
37013709
}
37023710

3703-
void IRGenDebugInfoImpl::emitTypeMetadata(IRGenFunction &IGF,
3704-
llvm::Value *Metadata, unsigned Depth,
3705-
unsigned Index, StringRef Name) {
3711+
void IRGenDebugInfoImpl::emitArtificialVariable(IRGenFunction &IGF,
3712+
llvm::Value *Metadata,
3713+
StringRef Name,
3714+
StringRef Identifier) {
37063715
if (Opts.DebugInfoLevel <= IRGenDebugInfoLevel::LineTables)
37073716
return;
37083717

@@ -3711,23 +3720,45 @@ void IRGenDebugInfoImpl::emitTypeMetadata(IRGenFunction &IGF,
37113720
if (!DS || DS->getInlinedFunction()->isTransparent())
37123721
return;
37133722

3714-
llvm::SmallString<8> Buf;
3715-
static const char *Tau = SWIFT_UTF8("\u03C4");
3716-
llvm::raw_svector_ostream OS(Buf);
3717-
OS << '$' << Tau << '_' << Depth << '_' << Index;
3718-
uint64_t PtrWidthInBits = CI.getTargetInfo().getPointerWidth(clang::LangAS::Default);
3723+
auto id = IGF.getSwiftModule()->getASTContext().getIdentifier(Name);
3724+
uint64_t PtrWidthInBits =
3725+
CI.getTargetInfo().getPointerWidth(clang::LangAS::Default);
37193726
assert(PtrWidthInBits % 8 == 0);
37203727
auto DbgTy = DebugTypeInfo::getTypeMetadata(
3721-
getMetadataType(Name)->getDeclaredInterfaceType().getPointer(),
3728+
getMetadataType(Identifier)->getDeclaredInterfaceType().getPointer(),
37223729
Size(PtrWidthInBits / 8),
37233730
Alignment(CI.getTargetInfo().getPointerAlign(clang::LangAS::Default)));
3724-
emitVariableDeclaration(IGF.Builder, Metadata, DbgTy, IGF.getDebugScope(),
3725-
{}, {OS.str().str(), 0, false},
3726-
// swift.type is already a pointer type,
3727-
// having a shadow copy doesn't add another
3728-
// layer of indirection.
3729-
IGF.isAsync() ? CoroDirectValue : DirectValue,
3730-
ArtificialValue);
3731+
emitVariableDeclaration(
3732+
IGF.Builder, Metadata, DbgTy, IGF.getDebugScope(), {},
3733+
{id.str(), 0, false}, // swift.type is already a pointer type,
3734+
// having a shadow copy doesn't add another
3735+
// layer of indirection.
3736+
IGF.isAsync() ? CoroDirectValue : DirectValue, ArtificialValue);
3737+
}
3738+
3739+
void IRGenDebugInfoImpl::emitTypeMetadata(IRGenFunction &IGF,
3740+
llvm::Value *Metadata, unsigned Depth,
3741+
unsigned Index, StringRef Name) {
3742+
llvm::SmallString<8> Buf;
3743+
static const char *Tau = SWIFT_UTF8("\u03C4");
3744+
llvm::raw_svector_ostream OS(Buf);
3745+
OS << '$' << Tau << '_' << Depth << '_' << Index;
3746+
3747+
emitArtificialVariable(IGF, Metadata, OS.str(), Name);
3748+
}
3749+
3750+
void IRGenDebugInfoImpl::emitWitnessTable(IRGenFunction &IGF,
3751+
llvm::Value *Metadata, unsigned Depth,
3752+
unsigned Index,
3753+
ProtocolDecl *protocol) {
3754+
llvm::SmallString<64> Buf;
3755+
static const char *Tau = SWIFT_UTF8("\u03C4");
3756+
llvm::raw_svector_ostream OS(Buf);
3757+
DebugTypeInfo DbgTy(protocol->getInterfaceType());
3758+
auto MangledName = getMangledName(DbgTy);
3759+
OS << "$WT_" << Tau << '_' << Depth << '_' << Index << "_" << MangledName;
3760+
3761+
emitArtificialVariable(IGF, Metadata, OS.str(), Buf.str());
37313762
}
37323763

37333764
void IRGenDebugInfoImpl::emitPackCountParameter(IRGenFunction &IGF,
@@ -3872,6 +3903,13 @@ void IRGenDebugInfo::emitTypeMetadata(IRGenFunction &IGF, llvm::Value *Metadata,
38723903
Depth, Index, Name);
38733904
}
38743905

3906+
void IRGenDebugInfo::emitWitnessTable(IRGenFunction &IGF, llvm::Value *Metadata,
3907+
unsigned Depth, unsigned Index,
3908+
ProtocolDecl *protocol) {
3909+
static_cast<IRGenDebugInfoImpl *>(this)->emitWitnessTable(
3910+
IGF, Metadata, Depth, Index, protocol);
3911+
}
3912+
38753913
void IRGenDebugInfo::emitPackCountParameter(IRGenFunction &IGF,
38763914
llvm::Value *Metadata,
38773915
SILDebugVariable VarInfo) {

lib/IRGen/IRGenDebugInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ class IRGenDebugInfo {
188188
void emitTypeMetadata(IRGenFunction &IGF, llvm::Value *Metadata,
189189
unsigned Depth, unsigned Index, StringRef Name);
190190

191+
/// Emit debug metadata for a (protocol) witness table.
192+
void emitWitnessTable(IRGenFunction &IGF, llvm::Value *Metadata,
193+
unsigned Depth, unsigned Index, ProtocolDecl *protocol);
194+
191195
/// Emit debug info for the IR function parameter holding the size of one or
192196
/// more parameter / type packs.
193197
void emitPackCountParameter(IRGenFunction &IGF, llvm::Value *Metadata,

lib/IRGen/IRGenSIL.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,14 @@ class IRGenSILFunction :
11321132
}
11331133

11341134
emitTypeMetadataRef(archetype);
1135+
1136+
for (auto protocol : archetype->getConformsTo()) {
1137+
auto conformance =
1138+
ProtocolConformanceRef::forAbstract(archetype, protocol);
1139+
emitWitnessTableRef(*this, archetype->getCanonicalType(),
1140+
conformance);
1141+
}
1142+
11351143
} else if (auto packArchetype = dyn_cast<PackArchetypeType>(t)) {
11361144
emitTypeMetadataRef(packArchetype);
11371145
} else if (auto packtype = dyn_cast<SILPackType>(t)) {

lib/IRGen/LocalTypeData.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -412,9 +412,13 @@ static void maybeEmitDebugInfoForLocalTypeData(IRGenFunction &IGF,
412412
if (DS && DS->getInlinedFunction() &&
413413
DS->getInlinedFunction()->isTransparent())
414414
return;
415-
416-
// Only for formal type metadata.
417-
if (key.Kind != LocalTypeDataKind::forFormalTypeMetadata())
415+
// For formal type metadata and witness tables.
416+
ProtocolDecl *proto = nullptr;
417+
if (key.Kind.isAbstractProtocolConformance())
418+
proto = key.Kind.getAbstractProtocolConformance();
419+
else if (key.Kind.isConcreteProtocolConformance())
420+
proto = key.Kind.getConcreteProtocolConformance()->getProtocol();
421+
else if (key.Kind != LocalTypeDataKind::forFormalTypeMetadata())
418422
return;
419423

420424
// Only for archetypes, and not for opened/opaque archetypes.
@@ -447,10 +451,12 @@ static void maybeEmitDebugInfoForLocalTypeData(IRGenFunction &IGF,
447451
if (!IGF.IGM.DebugInfo)
448452
return;
449453

450-
IGF.IGM.DebugInfo->emitTypeMetadata(IGF, data,
451-
typeParam->getDepth(),
452-
typeParam->getIndex(),
453-
name);
454+
if (proto) {
455+
IGF.IGM.DebugInfo->emitWitnessTable(IGF, data, typeParam->getDepth(),
456+
typeParam->getIndex(), proto);
457+
} else
458+
IGF.IGM.DebugInfo->emitTypeMetadata(IGF, data, typeParam->getDepth(),
459+
typeParam->getIndex(), name);
454460
}
455461

456462
void

test/DebugInfo/witness_table.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s
2+
import StdlibUnittest
3+
protocol P1 {}
4+
protocol P2 {}
5+
protocol P3 {}
6+
protocol P4 {}
7+
protocol P5 {}
8+
9+
struct I: P1, P2, P4 {}
10+
struct I2: P3 {}
11+
struct I3: P5 {}
12+
13+
struct S<T, U: P3> where T: P1, T: P2 {
14+
let t: T
15+
let u: U
16+
17+
func foo() {
18+
}
19+
//CHECK: ![[foo:[0-9]+]] = distinct !DISubprogram(name: "foo", linkageName: "$s13witness_table1SV3fooyyF",
20+
//CHECK: !DILocalVariable(name: "$\CF\84_0_0", scope: ![[foo]], {{.*}}, flags: DIFlagArtificial)
21+
//CHECK: !DILocalVariable(name: "$WT_\CF\84_0_0_$s13witness_table2P1_pmD", scope: ![[foo]], {{.*}}, flags: DIFlagArtificial)
22+
//CHECK: !DILocalVariable(name: "$WT_\CF\84_0_0_$s13witness_table2P2_pmD", scope: ![[foo]], {{.*}}, flags: DIFlagArtificial)
23+
//CHECK: !DILocalVariable(name: "$\CF\84_0_1", scope: ![[foo]], {{.*}}, flags: DIFlagArtificial)
24+
//CHECK: !DILocalVariable(name: "$WT_\CF\84_0_1_$s13witness_table2P3_pmD", scope: ![[foo]], {{.*}}, flags: DIFlagArtificial)
25+
26+
func bar<V: P4>(v: V) {
27+
}
28+
//CHECK: ![[bar:[0-9]+]] = distinct !DISubprogram(name: "bar", linkageName: "$s13witness_table1SV3bar1vyqd___tAA2P4Rd__lF",
29+
//CHECK: !DILocalVariable(name: "$\CF\84_1_0", scope: ![[bar]], {{.*}}, flags: DIFlagArtificial)
30+
//CHECK: !DILocalVariable(name: "$WT_\CF\84_1_0_$s13witness_table2P4_pmD", scope: ![[bar]], {{.*}}, flags: DIFlagArtificial)
31+
//CHECK: !DILocalVariable(name: "$\CF\84_0_0", scope: ![[bar]], {{.*}}, flags: DIFlagArtificial)
32+
//CHECK: !DILocalVariable(name: "$WT_\CF\84_0_0_$s13witness_table2P1_pmD", scope: ![[bar]], {{.*}}, flags: DIFlagArtificial)
33+
//CHECK: !DILocalVariable(name: "$WT_\CF\84_0_0_$s13witness_table2P2_pmD", scope: ![[bar]], {{.*}}, flags: DIFlagArtificial)
34+
//CHECK: !DILocalVariable(name: "$\CF\84_0_1", scope: ![[bar]], {{.*}}, flags: DIFlagArtificial)
35+
//CHECK: !DILocalVariable(name: "$WT_\CF\84_0_1_$s13witness_table2P3_pmD", scope: ![[bar]], {{.*}}, flags: DIFlagArtificial)
36+
}
37+
38+
39+
extension S where T: P5 {
40+
func baz() {
41+
}
42+
43+
//CHECK: ![[baz:[0-9]+]] = distinct !DISubprogram(name: "baz", linkageName: "$s13witness_table1SVA2A2P5RzrlE3bazyyF",
44+
//CHECK: !DILocalVariable(name: "$WT_\CF\84_0_0_$s13witness_table2P5_pmD", scope: ![[baz]], {{.*}}, flags: DIFlagArtificial)
45+
//CHECK: !DILocalVariable(name: "$\CF\84_0_0", scope: ![[baz]], {{.*}}, flags: DIFlagArtificial)
46+
//CHECK: !DILocalVariable(name: "$WT_\CF\84_0_0_$s13witness_table2P1_pmD", scope: ![[baz]], {{.*}}, flags: DIFlagArtificial)
47+
//CHECK: !DILocalVariable(name: "$WT_\CF\84_0_0_$s13witness_table2P2_pmD", scope: ![[baz]], {{.*}}, flags: DIFlagArtificial)
48+
//CHECK: !DILocalVariable(name: "$\CF\84_0_1", scope: ![[baz]], {{.*}}, flags: DIFlagArtificial)
49+
//CHECK: !DILocalVariable(name: "$WT_\CF\84_0_1_$s13witness_table2P3_pmD", scope: ![[baz]], {{.*}}, flags: DIFlagArtificial)
50+
}
51+
52+
S(t: I(), u: I2())
53+
54+
func freeFunc<T1: P1, T2>(t1: T1, t2: T2) where T2: P3, T2: P4 {
55+
}
56+
//CHECK: ![[freeFunc:[0-9]+]] = distinct !DISubprogram(name: "freeFunc", linkageName: "$s13witness_table8freeFunc2t12t2yx_q_tAA2P1RzAA2P3R_AA2P4R_r0_lF",
57+
//CHECK: !DILocalVariable(name: "$\CF\84_0_0", scope: ![[freeFunc]], {{.*}}, flags: DIFlagArtificial)
58+
//CHECK: !DILocalVariable(name: "$\CF\84_0_1", scope: ![[freeFunc]], {{.*}}, flags: DIFlagArtificial)
59+
//CHECK: !DILocalVariable(name: "$WT_\CF\84_0_0_$s13witness_table2P1_pmD", scope: ![[freeFunc]], {{.*}}, flags: DIFlagArtificial)
60+
//CHECK: !DILocalVariable(name: "$WT_\CF\84_0_1_$s13witness_table2P3_pmD", scope: ![[freeFunc]], {{.*}}, flags: DIFlagArtificial)
61+
//CHECK: !DILocalVariable(name: "$WT_\CF\84_0_1_$s13witness_table2P4_pmD", scope: ![[freeFunc]], {{.*}}, flags: DIFlagArtificial)

0 commit comments

Comments
 (0)