Skip to content

Commit 60c2999

Browse files
committed
Add debug info support for inlined and specialized generic variables.
This patch adds SIL-level debug info support for variables whose static type is rewritten by an optimizer transformation. When a function is (generic-)specialized or inlined, the static types of inlined variables my change as they are remapped into the generic environment of the inlined call site. With this patch all inlined SILDebugScopes that point to functions with a generic signature are recursively rewritten to point to clones of the original function with new unique mangled names. The new mangled names consist of the old mangled names plus the new substituions, similar (or exactly, respectively) to how generic specialization is handled. On libSwiftCore.dylib (x86_64), this yields a 17% increase in unique source vars and a ~24% increase in variables with a debug location. rdar://problem/28859432 rdar://problem/34526036
1 parent d2cc353 commit 60c2999

File tree

18 files changed

+282
-70
lines changed

18 files changed

+282
-70
lines changed

docs/ABI/Mangling.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,7 @@ Function Specializations
787787

788788
specialization ::= type '_' type* 'Tg' SPEC-INFO // Generic re-abstracted specialization
789789
specialization ::= type '_' type* 'TG' SPEC-INFO // Generic not re-abstracted specialization
790+
specialization ::= type '_' type* 'Ti' SPEC-INFO // Inlined function with generic substitutions.
790791

791792
The types are the replacement types of the substitution list.
792793

include/swift/AST/SubstitutionMap.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ class SubstitutionMap {
153153
/// existential.
154154
bool hasOpenedExistential() const;
155155

156-
/// Query whether any replacement type sin the map contain dynamic Self.
156+
/// Query whether any replacement types in the map contain dynamic Self.
157157
bool hasDynamicSelf() const;
158158

159159
/// Whether the replacement types are all canonical.

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ NODE(ResilientProtocolWitnessTable)
8787
NODE(GenericSpecialization)
8888
NODE(GenericSpecializationNotReAbstracted)
8989
NODE(GenericSpecializationParam)
90+
NODE(InlinedGenericFunction)
9091
NODE(GenericTypeMetadataPattern)
9192
CONTEXT_NODE(Getter)
9293
NODE(Global)

include/swift/SIL/TypeSubstCloner.h

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "swift/SIL/SILCloner.h"
2525
#include "swift/SIL/DynamicCasts.h"
2626
#include "swift/SILOptimizer/Utils/Local.h"
27+
#include "swift/SILOptimizer/Utils/SpecializationMangler.h"
2728
#include "llvm/Support/Debug.h"
2829

2930
namespace swift {
@@ -277,6 +278,84 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
277278
super::visitDestroyValueInst(Destroy);
278279
}
279280

281+
/// One abstract function in the debug info can only have one set of variables
282+
/// and types. This function determines whether applying the substitutions in
283+
/// \p SubsMap on the generic signature \p Sig will change the generic type
284+
/// parameters in the signature. This is used to decide whether it's necessary
285+
/// to clone a unique copy of the function declaration with the substitutions
286+
/// applied for the debug info.
287+
static bool substitutionsChangeGenericTypeParameters(SubstitutionMap SubsMap,
288+
GenericSignature *Sig) {
289+
290+
// If there are no substitutions, just reuse
291+
// the original decl.
292+
if (SubsMap.empty())
293+
return false;
294+
295+
auto Params = Sig->getSubstitutableParams();
296+
return std::any_of(Params.begin(), Params.end(), [&](Type ParamType) {
297+
Type Substitution = Type(ParamType).subst(SubsMap);
298+
return !Substitution->isOpenedExistential() &&
299+
(Substitution->getCanonicalType() !=
300+
ParamType->getCanonicalType());
301+
});
302+
}
303+
304+
enum { ForInlining = true };
305+
/// Helper function to clone the parent function of a SILDebugScope if
306+
/// necessary when inlining said function into a new generic context.
307+
/// \param SubsMap - the substitutions of the inlining/specialization process.
308+
/// \param RemappedSig - the generic signature
309+
static SILFunction *remapParentFunction(SILModule &M,
310+
SILFunction *ParentFunction,
311+
SubstitutionMap SubsMap,
312+
GenericSignature *RemappedSig,
313+
bool ForInlining = false) {
314+
// If the original, non-inlined version of the function had no generic
315+
// environment, there is no need to remap it.
316+
auto *OriginalEnvironment = ParentFunction->getGenericEnvironment();
317+
if (!RemappedSig || !OriginalEnvironment)
318+
return ParentFunction;
319+
320+
if (SubsMap.hasArchetypes())
321+
SubsMap = SubsMap.mapReplacementTypesOutOfContext();
322+
323+
if (!substitutionsChangeGenericTypeParameters(SubsMap, RemappedSig))
324+
return ParentFunction;
325+
326+
// Clone the function with the substituted type for the debug info.
327+
Mangle::GenericSpecializationMangler Mangler(
328+
ParentFunction, SubsMap, IsNotSerialized, false, ForInlining);
329+
std::string MangledName = Mangler.mangle(RemappedSig);
330+
331+
if (ParentFunction->getName() == MangledName)
332+
return ParentFunction;
333+
if (auto *CachedFn = M.lookUpFunction(MangledName))
334+
ParentFunction = CachedFn;
335+
else {
336+
// Create a new function with this mangled name with an empty
337+
// body. There won't be any IR generated for it (hence the linkage),
338+
// but the symbol will be refered to by the debug info metadata.
339+
ParentFunction = M.getOrCreateFunction(
340+
ParentFunction->getLocation(), MangledName, SILLinkage::Shared,
341+
ParentFunction->getLoweredFunctionType(), ParentFunction->isBare(),
342+
ParentFunction->isTransparent(), ParentFunction->isSerialized(), 0,
343+
ParentFunction->isThunk(), ParentFunction->getClassSubclassScope());
344+
// Increment the ref count for the inlined function, so it doesn't
345+
// get deleted before we can emit abstract debug info for it.
346+
if (!ParentFunction->isZombie()) {
347+
ParentFunction->setInlined();
348+
// If the function was newly created with an empty body mark it as
349+
// undead.
350+
if (ParentFunction->empty()) {
351+
M.eraseFunction(ParentFunction);
352+
ParentFunction->setGenericEnvironment(OriginalEnvironment);
353+
}
354+
}
355+
}
356+
return ParentFunction;
357+
}
358+
280359
/// The Swift module that the cloned function belongs to.
281360
ModuleDecl *SwiftMod;
282361
/// The substitutions list for the specialization.
@@ -287,7 +366,7 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
287366
SILFunction &Original;
288367
/// True, if used for inlining.
289368
bool Inlining;
290-
};
369+
};
291370

292371
} // end namespace swift
293372

include/swift/SILOptimizer/Utils/GenericCloner.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class GenericCloner : public TypeSubstCloner<GenericCloner> {
3434
IsSerialized_t Serialized;
3535
const ReabstractionInfo &ReInfo;
3636
CloneCollector::CallbackType Callback;
37+
llvm::SmallDenseMap<const SILDebugScope *, const SILDebugScope *, 8>
38+
RemappedScopeCache;
3739

3840
public:
3941
friend class SILCloner<GenericCloner>;
@@ -90,6 +92,9 @@ class GenericCloner : public TypeSubstCloner<GenericCloner> {
9092
/// by initCloned.
9193
void populateCloned();
9294
SILFunction *getCloned() { return &getBuilder().getFunction(); }
95+
96+
const SILDebugScope *remapScope(const SILDebugScope *DS);
97+
9398
};
9499

95100
} // end namespace swift

include/swift/SILOptimizer/Utils/SpecializationMangler.h

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ class SpecializationMangler : public Mangle::ASTMangler {
4848
protected:
4949
SpecializationMangler(SpecializationPass P, IsSerialized_t Serialized,
5050
SILFunction *F)
51-
: Pass(P), Serialized(Serialized), Function(F), ArgOpBuffer(ArgOpStorage) {}
51+
: Pass(P), Serialized(Serialized), Function(F),
52+
ArgOpBuffer(ArgOpStorage) {}
5253

5354
SILFunction *getFunction() const { return Function; }
5455

@@ -67,17 +68,17 @@ class GenericSpecializationMangler : public SpecializationMangler {
6768

6869
SubstitutionMap SubMap;
6970
bool isReAbstracted;
71+
bool isInlined;
7072

7173
public:
72-
73-
GenericSpecializationMangler(SILFunction *F,
74-
SubstitutionMap SubMap,
75-
IsSerialized_t Serialized,
76-
bool isReAbstracted)
77-
: SpecializationMangler(SpecializationPass::GenericSpecializer, Serialized, F),
78-
SubMap(SubMap), isReAbstracted(isReAbstracted) {}
79-
80-
std::string mangle();
74+
GenericSpecializationMangler(SILFunction *F, SubstitutionMap SubMap,
75+
IsSerialized_t Serialized, bool isReAbstracted,
76+
bool isInlined = false)
77+
: SpecializationMangler(SpecializationPass::GenericSpecializer,
78+
Serialized, F),
79+
SubMap(SubMap), isReAbstracted(isReAbstracted), isInlined(isInlined) {}
80+
81+
std::string mangle(GenericSignature *Sig = nullptr);
8182
};
8283

8384
class PartialSpecializationMangler : public SpecializationMangler {
@@ -88,10 +89,10 @@ class PartialSpecializationMangler : public SpecializationMangler {
8889
public:
8990
PartialSpecializationMangler(SILFunction *F,
9091
CanSILFunctionType SpecializedFnTy,
91-
IsSerialized_t Serialized,
92-
bool isReAbstracted)
93-
: SpecializationMangler(SpecializationPass::GenericSpecializer, Serialized, F),
94-
SpecializedFnTy(SpecializedFnTy), isReAbstracted(isReAbstracted) {}
92+
IsSerialized_t Serialized, bool isReAbstracted)
93+
: SpecializationMangler(SpecializationPass::GenericSpecializer,
94+
Serialized, F),
95+
SpecializedFnTy(SpecializedFnTy), isReAbstracted(isReAbstracted) {}
9596

9697
std::string mangle();
9798
};

lib/Demangling/Demangler.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,11 +1734,13 @@ NodePointer Demangler::demangleThunkOrSpecialization() {
17341734
Thunk = addChild(Thunk, popNode(Node::Kind::Type));
17351735
return addChild(Thunk, Ty2);
17361736
}
1737-
case'g':
1737+
case 'g':
17381738
return demangleGenericSpecialization(Node::Kind::GenericSpecialization);
1739-
case'G':
1739+
case 'G':
17401740
return demangleGenericSpecialization(Node::Kind::
17411741
GenericSpecializationNotReAbstracted);
1742+
case 'i':
1743+
return demangleGenericSpecialization(Node::Kind::InlinedGenericFunction);
17421744
case'p': {
17431745
NodePointer Spec = demangleSpecAttributes(Node::Kind::
17441746
GenericPartialSpecialization);
@@ -1869,7 +1871,8 @@ NodePointer Demangler::demangleGenericSpecialization(Node::Kind SpecKind) {
18691871
if (!TyList)
18701872
return nullptr;
18711873
for (NodePointer Ty : *TyList) {
1872-
Spec->addChild(createWithChild(Node::Kind::GenericSpecializationParam, Ty), *this);
1874+
Spec->addChild(createWithChild(Node::Kind::GenericSpecializationParam, Ty),
1875+
*this);
18731876
}
18741877
return Spec;
18751878
}

lib/Demangling/NodePrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ class NodePrinter {
351351
case Node::Kind::GenericSpecialization:
352352
case Node::Kind::GenericSpecializationNotReAbstracted:
353353
case Node::Kind::GenericSpecializationParam:
354+
case Node::Kind::InlinedGenericFunction:
354355
case Node::Kind::GenericTypeMetadataPattern:
355356
case Node::Kind::Getter:
356357
case Node::Kind::Global:
@@ -1183,6 +1184,9 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
11831184
case Node::Kind::GenericSpecializationNotReAbstracted:
11841185
printSpecializationPrefix(Node, "generic not re-abstracted specialization");
11851186
return nullptr;
1187+
case Node::Kind::InlinedGenericFunction:
1188+
printSpecializationPrefix(Node, "inlined generic function");
1189+
return nullptr;
11861190
case Node::Kind::SpecializationIsFragile:
11871191
Printer << "preserving fragile attribute";
11881192
return nullptr;

lib/Demangling/OldRemangler.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ void Remangler::mangleGenericSpecialization(Node *node) {
534534
// Start another mangled name.
535535
Out << "__T";
536536
}
537+
537538
void Remangler::mangleGenericSpecializationNotReAbstracted(Node *node) {
538539
Out << "TSr";
539540
mangleChildNodes(node); // GenericSpecializationParams
@@ -545,6 +546,17 @@ void Remangler::mangleGenericSpecializationNotReAbstracted(Node *node) {
545546
Out << "__T";
546547
}
547548

549+
void Remangler::mangleInlinedGenericFunction(Node *node) {
550+
Out << "TSi";
551+
mangleChildNodes(node); // GenericSpecializationParams
552+
553+
// Specializations are just prepended to already-mangled names.
554+
resetSubstitutions();
555+
556+
// Start another mangled name.
557+
Out << "__T";
558+
}
559+
548560
void Remangler::mangleGenericPartialSpecialization(Node *node) {
549561
unreachable("todo");
550562
}

lib/Demangling/Remangler.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,8 +1122,20 @@ void Remangler::mangleGenericSpecialization(Node *node) {
11221122
}
11231123
assert(!FirstParam && "generic specialization with no substitutions");
11241124

1125-
Buffer << (node->getKind() ==
1126-
Node::Kind::GenericSpecializationNotReAbstracted ? "TG" : "Tg");
1125+
switch (node->getKind()) {
1126+
case Node::Kind::GenericSpecialization:
1127+
Buffer << "Tg";
1128+
break;
1129+
case Node::Kind::GenericSpecializationNotReAbstracted:
1130+
Buffer << "TG";
1131+
break;
1132+
case Node::Kind::InlinedGenericFunction:
1133+
Buffer << "Ti";
1134+
break;
1135+
default:
1136+
unreachable("unsupported node");
1137+
}
1138+
11271139
for (NodePointer Child : *node) {
11281140
if (Child->getKind() != Node::Kind::GenericSpecializationParam)
11291141
mangle(Child);
@@ -1134,6 +1146,11 @@ void Remangler::mangleGenericSpecializationNotReAbstracted(Node *node) {
11341146
mangleGenericSpecialization(node);
11351147
}
11361148

1149+
void Remangler::mangleInlinedGenericFunction(Node *node) {
1150+
mangleGenericSpecialization(node);
1151+
}
1152+
1153+
11371154
void Remangler::mangleGenericSpecializationParam(Node *node) {
11381155
unreachable("handled inline");
11391156
}
@@ -1161,6 +1178,7 @@ void Remangler::mangleGlobal(Node *node) {
11611178
case Node::Kind::FunctionSignatureSpecialization:
11621179
case Node::Kind::GenericSpecialization:
11631180
case Node::Kind::GenericSpecializationNotReAbstracted:
1181+
case Node::Kind::InlinedGenericFunction:
11641182
case Node::Kind::GenericPartialSpecialization:
11651183
case Node::Kind::GenericPartialSpecializationNotReAbstracted:
11661184
case Node::Kind::OutlinedBridgedMethod:

0 commit comments

Comments
 (0)